I don't feel like I have clarity on what EWG supports or does not support changing here (neither from an implementer's perspective nor from the perspective of a contributor to SG12).

The status quo in the standard is:
1) Language linkage is part of the function type.
2) Initializing a function pointer with a wrong-language-linkage function (pointer) is a type error.
3) Explicitly casting a function pointer to the wrong type and calling it is UB.

The status quo in implementations is mostly that (1) is not implemented for C language linkage, but that (2) is enforced for calling conventions that are part of function types. And I expect every implementation has some carve-outs for (3) in that they accept somewhat-different function types at caller versus callee (for example, the pointee types of pointer parameters may be permitted to vary in some ways).

The only part of this that seems to obviously be in scope for SG12 is point (3), but that's not where the problem lies. Making (3) be conditionally-supported rather than UB does not address the issue, because programs like

extern "C" void f();
void g(void (*)());
int main() { g(f()); }

... would still be ill-formed due to the type mismatch from (1) + (2). The implementations that ignore point (1) today would presumably still ignore point (1) and accept the program (so we never reach (3) because the types match). The implementations that implement point (1) today do so because the types are meaningfully different, and so they would continue to treat the call as UB.

So any change to point (3) seems to be irrelevant if we don't also change (1) or (2).

If we want to address this, it seems to me that we need to look at points (1) and (2), which seem like EWG questions not SG12 questions to me. And it sounds like the EWG telecon said that they're not prepared to make (1) or (2) conditionally-supported (rejecting CWG's suggested approach), but might be prepared to remove (some unspecified rule). So I think the leaves only a few options:

(a) the status quo: the standard continues to say the same thing and vendors continue to ignore it,
(b) we remove point (1) above and break the targets relying on it, or
(c) we remove point (2) above.

Option (c) would result in an SG12 question (what should happen if you implicitly convert a function pointer with one language linkage to a function pointer with a different language linkage and try to call it?). Is that what we're being asked? I think there's only one possible answer: that is UB, at least for the implementations where it results in a different calling convention. Making it conditionally-supported (or more concretely, an implementation-defined choice of UB or as if the calling conventions match) would mean it's still UB for code that wishes to be portable -- which seems like a regression, since such obviously-not-type-safe code used to be ill-formed. The situation would be strictly better if we made point (2) conditionally-supported instead: then the same code would still build and work on the same targets, but on the targets where it doesn't work, you'd get an error at compile time instead of UB at runtime.

So I don't think there's anything that SG12 can do to avoid option (c) being strictly worse than the "conditionally-supported" approach that EWG already expressed a dislike for, and none of the other options are in SG12's domain.

Given the above, I think realistically EWG needs to choose between (a) (ie, all major implementations continue to ignore the standard rules), (b) (ie, at least one target cannot implement the C++ rules without a severe ABI break), conditionally-supported-(a) (which Hubert suggests was not considered), or conditionally-supported-(b) (ie, what CWG asked for and EWG said no to).

To me it seems like (a) and (b) are not acceptable resolutions, and EWG didn't like conditionally-supported-(b). So maybe we should be considering conditionally-supported-(a) (which would simply be standardizing existing practice).

On Wed, May 13, 2020 at 1:11 PM Gabriel Dos Reis via SG12 <sg12@lists.isocpp.org> wrote:
My inclination would  be to upgrade the behavior from UB to conditionally supported, but not further (e.g. no outright removal).

-- Gaby

From: SG12 <sg12-bounces@lists.isocpp.org> on behalf of Keane, Erich via SG12 <sg12@lists.isocpp.org>
Sent: Wednesday, April 15, 2020 8:55:54 AM
To: sg12@lists.isocpp.org <sg12@lists.isocpp.org>
Cc: Keane, Erich <erich.keane@intel.com>
Subject: [SG12] EWG Requests feedback/suggestions on Core Issue 1555

Hi SG12-

In the EWG telecon today, we discussed core issue 1555 (http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1555). The summary of the issue is that the standard makes function types of different language linkage incompatible, thus calling a function from a pointer with different language linkage is undefined behavior.  One unnamed implementation was referenced during the discussion where language linkage effects calling convention. 


The major implementations (and none other than the 1 unnamed one listed) simply don’t implement this restriction (that the types aren’t compatible) because the calling convention is the same between the linkages.


EWG was undecided as to whether we should remove this instance restriction, or leave it as undefined behavior.  None seemed to support CWG1555’s proposed resolution of conditionally-supported behavior.


(TL-DR people can start here😊 )

The outcome of the discussion is that the impact and scope of this Undefined Behavior should be evaluated by SG12, and if possible, provide a set of recommendations for dealing with this core issue.



SG12 mailing list
Subscription: https://lists.isocpp.org/mailman/listinfo.cgi/sg12
Link to this post: http://lists.isocpp.org/sg12/2020/05/0906.php