Skip to content

CWG2715 [expr.call] "Calling function" is not clearly defined, and may not exist #287

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

Closed
t3nsor opened this issue Apr 2, 2023 · 4 comments · Fixed by cplusplus/draft#6328

Comments

@t3nsor
Copy link

t3nsor commented Apr 2, 2023

Full name of submitter: Brian Bi

Reference (section label): [expr.call]

Issue description: [expr.call]/6 states: "[...] The initialization and destruction of each parameter occurs within the context of the calling function." However, a function call that is a subexpression of an init-declarator for a non-local variable does not have a calling function, and some expressions that are evaluated during translation do not have calling functions:

class C {
  private:
    constexpr int C(int) {}
    friend void foo(int (*a)[1]) noexcept;
};

constexpr int bar(C) { return 1; }

void foo(int (&a)[bar(1)]) noexcept(bar(2) > 0);  // presumably OK because of friendship

Example 2 suggests that the purpose of this sentence is to clarify access control and exception handling. Are there any other language concepts that care about whether the context is that of the caller or the callee?

Suggested resolution:
Edit [expr.call]/6:

[...] It is implementation-defined whether the lifetime of a parameter ends when the function in which it is defined returns or at the end of the enclosing full-expression. For purposes of access control ([class.access.general]), tThe initialization and destruction of each parameter occurs within the context of the calling function full-expression to which it belongs ([intro.execution]).

[Example 2 : The access of the constructor, conversion functions or destructor is checked at the point of call in the calling function. If a constructor or destructor for a function parameter throws an exception, the search for a handler
starts in the calling function; in particular, if the function called has a function-try-block (14.1) with a handler that
can handle the exception, this handler is not considered.
end example]

[Note -?-: As specified in [except.throw], if a constructor or destructor for a function parameter throws an exception, the search for a handler starts in the calling function, if any; in particular, if the function called has a function-try-block ([except.pre]) with a handler that can handle the exception, this handler is not considered. —end note]

@jensmaurer
Copy link
Member

As specified in [except.throw]

Where exactly do we say that?

@jensmaurer
Copy link
Member

CWG2715

I've altered the proposed resolution so that it keeps the general thrust of "in the calling function" instead of limiting the normative rule to access control.

@jensmaurer jensmaurer changed the title [expr.call] "Calling function" is not clearly defined, and may not exist CWG2715 [expr.call] "Calling function" is not clearly defined, and may not exist Apr 9, 2023
@t3nsor
Copy link
Author

t3nsor commented Apr 9, 2023

As specified in [except.throw]

Where exactly do we say that?

http://eel.is/c++draft/except.throw#2 explains how to find the nearest handler. Any try-block or function-try-block has not been "entered" yet if the parameters are still being initialized.

@jensmaurer
Copy link
Member

jensmaurer commented Apr 9, 2023

Well, it still seems possible to (e.g.) destroy a parameter inside the called function, making the function-try-block relevant. We don't want that, so we should have a general rule that parameters are created and destroyed in the caller's context.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants