Transitioning libgomp from C to C++ implementation
Arsen Arsenović
arsen@aarsen.me
Sat May 9 10:39:54 GMT 2026
Hi Cristopher,
Christopher Bazley <chris.bazley@arm.com> writes:
> OK. If that's what libgomp needs, then that's what makes sense. If
> what libgomp needed were ad hoc polymorphism, then _Generic would be
> perfectly adequate.
Scarce few programs have no need for those. I can't think of many
programs that don't need lists but do need overloading.
> Callbacks and event handlers commonly have a parameter of type 'void
> *'. Requiring arguments of that type to be explicitly cast to some
> other pointer type makes source code harder to read and write, and
> actually detracts from type safety.
I see no difference between
T *userptr = userptr_voidstar;
... and:
auto userptr = static_cast<T *> (userptr_voidstar);
... in this regard.
In addition, unlike in C, it is possible to hide away the lossy type
games: https://godbolt.org/z/z5dzr93Eb
(the above is incomplete in a few obvious ways, but it's a quick sketch)
> Casting discards type information. Preventing implicit conversion of
> type 'void *' to other pointer types on assignment or initialisation
> prevents the compiler from checking that qualifiers weren't discarded,
> or even that the expression whose type is being cast actually has a
> pointer type.
>
> For example:
>
> void callback(const void *p)
> {
> int *q = (int *)p; // whoops!
> *q = 1;
> }
>
> void callback(long int p)
> {
> int *q = (int *)p; // whoops!
> *q = 1;
> }
Luckily neither of those are legal when using specific casts:
~$ g++ -S -o - -x c++ - <<< 'void f(const void *p) { auto x = static_cast<int *>(p); }'
.file "<stdin>"
<stdin>: In function ‘void f(const void*)’:
<stdin>:1:34: error: ‘static_cast’ from type ‘const void*’ to type ‘int*’ casts away qualifiers
~ 1 $ g++ -S -o - -x c++ - <<< 'void f(long int p) { auto x = static_cast<int *>(p); }'
.file "<stdin>"
<stdin>: In function ‘void f(long int)’:
<stdin>:1:31: error: invalid ‘static_cast’ from type ‘long int’ to type ‘int*’
~ 1 $ g++ -S -o - -x c++ - <<< 'void f(__UINTPTR_TYPE__ p) { auto x = static_cast<int *>(p); }'
.file "<stdin>"
<stdin>: In function ‘void f(long unsigned int)’:
<stdin>:1:39: error: invalid ‘static_cast’ from type ‘long unsigned int’ to type ‘int*’
~ 1 $
> I believe that the concept of any-type (as expressed via void *) is orthogonal
> to the concept of qualified type or subtype. Python's treatment of the type
> annotation Any supports this point of view.
>
> This flaw in the design of C++ is also what necessitated the invention of
> nullptr, which would otherwise be unnecessary. Had the purpose of 'void *' not
> been misunderstood, nullptr could simply have been defined as a macro: ((void
> *)0).
OTOH, there's no benefit to omitting a 'nullptr' constant from the
language.
>>> - C++ constructors being unable to return a failure indication, and the
>>> gymnastics required to work around that without using exceptions (leading to
>>> many identically-named construction helpers).
>> I've been writing C++ in places where exceptions would be inconvenient
>> for many years now, and this is a fairly infrequent requirement IME.
>> It will be fine.
>
> Sorry but I'm not sure what you mean here.
>
> Are you saying that wanting to return a failure indication is
> infrequent, that doing without exceptions is infrequent, or both? I
> guess it depends what kind of code you are writing and what kind of
> system it runs on.
The former.
> Nowadays a lot of programmers would claim that malloc cannot fail, or
> at least that programs have no need to recover gracefully if it does
> fail. That does not apply to interactive programs running on operating
> systems that do not overcommit memory, but it might apply to
> non-interactive programs running on such systems.
Sure. And very often, types that hold pointers (e.g. for smart
pointers) can encode such a fail state. In cases where they cannot,
factory functions usually don't result in combinatorial explosion.
>>> - Erasure of designated initialisers that were vital for keeping the code
>>> readable and maintainable (by preventing definitions, for example array
>>> initialisers and enumerations, from diverging).
>> Designated initializers exist in C++.
>
> Not usefully, as far as I can tell: https://godbolt.org/z/7j6fdqzrb
I'm surprised GCC emits a sorry here, I hadn't noticed that.
> I find it frustrating that C++ lags more than a quarter of a century
> behind C in this respect. (I am aware why C++ does not allow arbitrary
> order of initialisers, but I do not see that as a point in its favour:
> debugging a mess caused by misordered constructor and destructor
> invocations is not fun.)
Such a "mess" is no different than the "mess" of relying on the
evaluation order of function arguments, except that in this case it's
more specified.
>>> - Gratuitous loss of the ability to find method definitions and usages using
>>> simple tools like 'grep'. (I do not mean gratuitous as a perjorative but in
>>> the specific sense that some useful patterns require subtype polymorphism, in
>>> which case the equivalent C code would have the same issue, but most code
>>> does not.)
>> There's no C pattern that is impossible in C++. There's certainly
>> nothing that requires dynamic dispatch that wouldn't require a
>> (hand-rolled) vtable in C.
>
> The issue is not impossibility but reduced maintainability of code
> that has fewer unique identifiers. It's possible to similarly reduce
> the maintainability of C programs by using structs to implement
> namespaces, and invoking functions via members. Most C programmers
> consider that the downsides outweigh any advantages.
I find memorizing many redundant identifiers isn't much better.
A name should name equivalent behavior in all contexts. A size is a
size. A push_back is a push_back. A pop_back is a pop_back.
>> Given that gcc is already in C++, it seems that that bridge was burned.
>
> It isn't as black and white as that. I know of at least one programmer who
> contributes to GCC because GCC is still largely written in the style of a C
> program, but does not feel inclined or able to contribute to Clang. He is
> probably unusual in that he is outspoken in his opinions.
Anecdotally, I've heard the opposite at least twice.
I have no doubt the phenomenon exists, but I am certain that the more
expressively powerful language allows for easier to write and
understand, and ergo higher quality, code long-term, with few or no
downsides.
--
Arsen Arsenović
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 288 bytes
Desc: not available
URL: <https://gcc.gnu.org/pipermail/gcc/attachments/20260509/de502a6c/attachment.sig>
More information about the Gcc
mailing list