Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[expr.call]/9 The result of a function call may not be the same as the result of the operand of its return statement #3124

Closed
sdkrystian opened this issue Aug 5, 2019 · 6 comments · Fixed by #3587
Assignees
Labels
cwg Issue must be reviewed by CWG.

Comments

@sdkrystian
Copy link
Contributor

sdkrystian commented Aug 5, 2019

[expr.call] p9 states:

The result of a function call is the result of the operand of the evaluated return statement in the called function [...]

However, this may not always work. For example:

int a = 0;
int f() 
{
  return a; // result of the operand a is an object
}
int b = f(); // function call is a prvalue, result should be a value, not an object

Additionally, if the result of the function is the result of the operand, then the wording in [stmt.return] p2 sentence 4 would have the operand initialize itself in the case of the function call and the operand being glvalues (the result of the function would be the result of the operand which would be the objects it denotes, so initializing the result of the function would initialize that object). Even crazier, in the case of the operand being a prvalue, this would have the operand initializing a value (result of the function would be the value of the operand).

To remedy this, it could be specified that the result of the function is the operand after any conversions are applied to the operand to convert it to the type and value category of the function call, but this could introduce some problems for prvalues, as they should not be materialized, and instead used to initialize the object itself.

Alternatively, the wording in [stmt.return] p2 sentence 4 could be removed entirely, and instead, [expr.call] p9 could be written to say:

If a function call is a prvalue, the result object is copy-initialized with the operand of the return statement. Otherwise, the glvalue result is the object denoted by t in some invented declaration T t = e; [Note: the lifetime of a temporary bound to this invented declaration is dictated by the lifetime rules for a temporary bound to a returned value of a function - end note] where e is the operand of the evaluated return statement and T is the return type of the function.

And this would solve the problem, as if the function call is a prvalue, the result would be its value, and if the function call is a glvalue, the result would simply be the object that the operand denoted, or the temporary that results from initializing the result.

@jensmaurer jensmaurer added the decision-required A decision of the editorial group (or the Project Editor) is required. label Sep 10, 2019
@jensmaurer jensmaurer removed the decision-required A decision of the editorial group (or the Project Editor) is required. label Sep 30, 2019
@zygoloid
Copy link
Member

zygoloid commented Sep 30, 2019

The result of the function call expression f() is the variable b. That is the same object that is initialized in the return-statement of the function. This is how the guaranteed copy elision mechanism works: the return-statement does directly initialize the object that the function call initializes. (Except for the special case in [class.temporary]p3 that permits a copy -- which does appear to be incorrect, in that it applies only to class types and should apply to all objects. I'm going to file a core issue for that.)

@sdkrystian
Copy link
Contributor Author

@zygoloid I don't really agree.

The result of the function call expression f() is the variable b

The result of a prvalue is "the value it stores into it's context". b is not a value. The result object would be the object denoted by b.

The operand of the return statement here is the glvalue a. The result of a glvalue is the entity that it denotes; in this case, an object. This does not match with the definition of what the result of a prvalue is (a value).

@sdkrystian
Copy link
Contributor Author

@zygoloid Addtionally, consider a situation like this:

float a = 0;
int f()
{
  return a;
}

int b = f();

Here, the "result of the operand of the evaluated return statement" is an object of type float. With the existing wording, that would make the result of the function call an object of type float too, even though it is a prvalue of type int, and prvalues are defined to result in a value.

@zygoloid
Copy link
Member

zygoloid commented Oct 1, 2019

OK, I see what you're saying now. Yes, it would be clearer if we said the result of the function call is the result of the possibly-converted operand of the evaluated return statement, or something like that.

There's another problem here: we can evaluate more than one return statement, in a case like

struct X { ~X() noexcept(false) { throw 0; } };
int f() {
  try {
    X x;
    return 1;
  } catch (int) {
    return 2;
  }
}

I think something like this would resolve the issue:

The result of a function call is the result of the possibly-converted operand of the evaluated return statement in that transferred control out of the called function

@zygoloid zygoloid reopened this Oct 1, 2019
@zygoloid zygoloid added the cwg Issue must be reviewed by CWG. label Oct 1, 2019
@jensmaurer jensmaurer self-assigned this Dec 28, 2019
@jensmaurer
Copy link
Member

The fix seems pretty obvious to me.

@sdkrystian
Copy link
Contributor Author

sdkrystian commented Jan 30, 2020

@jensmaurer @zygoloid Hm. I still don't believe the wording is quite fixed.

Consider what this means for a lvalue function call in conjunction with [stmt.return] p4, which says the result of the function call is initialized with the operand of the return statement... but we define the operand as being the result of the function call, and we end up saying that the operand initializes itself.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cwg Issue must be reviewed by CWG.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants