PR15105: __attribute__((noreturn)) and noreturn function types

Hi,

As PR15105 notes, our implementation of __attribute__((noreturn)) is
not entirely GCC-compatible. As far as I can tell, the situation in
GCC is:

GCC does not have a plain 'noreturn function' type.
__attribute__((noreturn)) on a function declaration makes that
declaration declare a noreturn function. It does not affect the
function's type.
__attribute__((noreturn)) on a function pointer or function reference
produces a 'pointer/reference to noreturn function' type.
GCC allows implicit conversions in either direction between
pointer-to-noreturn-function and pointer-to-function.

In Clang:

Clang *does* have a plain 'noreturn function' type.
__attribute__((noreturn)) on a function declaration makes that
declaration declare a noreturn function, and *adjusts the function
type* to be a noreturn function.
__attribute__((noreturn)) on a function pointer or function reference
produces a 'pointer/reference to noreturn function' type.
Clang allows a pointer-to-noreturn-function to implicitly convert to a
pointer-to-function, but not vice versa.

So... Clang's approach is more sound and type-safe, but it's not
GCC-compatible. The difference reaches into the language semantics
(C++ templates can tell the difference between noreturn and
not-noreturn functions), and the ABI (GCC has a different mangling for
pointer-to-noreturn-function which Clang does not implement).

What do people think? Is our improved behavior here sufficient to
justify the GCC incompatibility, or should we switch to being GCC
compatible? Or pick some middle-ground -- perhaps we could continue to
diagnose pointer-to-function to pointer-to-noreturn-function
conversions, except where the source expression is directly taking the
address of a noreturn function?

Thanks!
Richard

How often does our "improved" behavior cause us to reject valid code?

If this is causing problems for someone in the wild (the PR suggests
that it is), IMO we should just be compatible with GCC.

Since as you pointed out it has ABI and language semantics effects,
incompatibility could have potentially serious consequences and the
safest bet is to just be compatible.

-- Sean Silva

How often does our "improved" behavior cause us to reject valid code?

That sounds very hard to quantify. But at least I don't believe anyone
has ever encountered the name mangling issue in the wild and reported
it as a bug.

If this is causing problems for someone in the wild (the PR suggests
that it is), IMO we should just be compatible with GCC.

Well, there are a number of ways we could proceed. I'm currently
swaying towards being largely GCC-compatible, but keeping our ban on
implicitly converting pointer-to-function to
pointer-to-noreturn-function (except in the cases where we can
trivially see that the source is a noreturn function).

We're not guided by language standards here, and GCC's model for this
is quite bizarre, probably because of the internal representational issues.
For example, they drop "noreturn" on member functions because volatile
functions are valid there, and I assume they get the subtype relationship
wrong because it's generally valid to add the volatile qualifier in
a pointer conversion.

If their model were any less broken, I might agree with the compatibility
argument. As it is, it seems like a major drop in functionality for a pretty
theoretical interoperation gain.

That said, I see no reason not to adopt their mangling as a special case
when mangling pointers and references to noreturn functions.

John.

Agreed on all points. We designed the model we wanted for noreturn, and I think it's still the right one. Perhaps we can instead convince GCC to fix their non-type-safe model :slight_smile:

  - Doug

OK. The C11 and C++11 noreturn attributes are much closer to GCC's
model than to ours (noreturn is not ever part of the type for the
standard attributes, so they're the same as GCC's attributes in the
places where they're valid). I guess we're going to have to put up
with having two different models of 'noreturn' in Clang in perpetuity.

This comment concerns me.

I'm not an expert on the new spec, but this doesn't match my (vague) understanding of how attributes are associated with declarations. Can you point me towards the relevant wording?

If this really is the way the C++11 spec handles it, I'd strongly suggest we switch to the GCC model. Having such a major inconsistency between the two attribute formats when one is supported by the spec seems undesirable.

Philip Reames

There might be other ways to improve the Clang model and make it more compatible with GCC. For example, remove noreturn from the type of a noreturn function declaration. Then, introduce an implicit conversion from declaration references to noreturn functions to noreturn function pointer/reference types. It's still sound, but closer to GCC.

Yes, that's what I was suggesting in my 'middle-ground' option, and is
still my preferred option. I no longer think the status quo is viable;
PR15105 notes that we're actually rejecting valid code as a result of
our current behavior, because we can't compile this:

  std::bind(std::exit, 0)