Converting _Atomic(type) to type
Asked Answered
G

0

7

Consider the following C code:

#include <stdatomic.h>

struct _opaque;
typedef struct _opaque *opaque;
struct container { _Atomic opaque x; };

struct container get_container();
void consume_opaque(opaque);

void test() {
    consume_opaque(get_container().x);
}

This fails to compile (Clang 16) with the error:

error: passing '_Atomic(opaque)' to parameter of incompatible type 'opaque' (aka 'struct _opaque *')

This code continues to fail to compile, even after trying to explicitly cast the argument: (opaque) get_container().x.

By contrast, consider the following:

#include <stdatomic.h>

struct _opaque;
typedef struct _opaque *opaque;
struct container { _Atomic opaque x; };

struct container *get_container();
void consume_opaque(opaque);

void test() {
    consume_opaque(get_container()->x);
}

This compiles perfectly fine and the compiler is apparently happy to convert get_container()->x but not get_container().x in the case where the container is returned by value.

Why is this the case? How can get the compiler to do the conversion in the first example without explicitly saving the return value of get_container() to a local variable?

Garnetgarnett answered 2/9, 2023 at 22:0 Comment(4)
GCC13 compiles it without any warnings: godbolt.org/z/s3oT7PMdx . But note that the asm does the lvalue-to-rvalue conversion of the _Atomic opaque x member with just a register to register mov rdi, rax, not an atomic load from memory. Because the _Atomic object only exists as a local temporary return value. In C, copying around whole structs does not respect stuff like volatile or _Atomic on their members, so you've managed to bypass the things that normally stop you from making copies of an atomic object (like how in C++, std::atomic has no copy constructor).Meow
Whoever is teaching you to write code such as struct _opaque apparently doesn't know that identifiers that start with an underscore at file scope are reserved: "All identifiers that begin with an underscore are always reserved for use as identifiers with file scope in both the ordinary and tag name spaces. "Redd
@PeterCordes I would be interested in knowing whether GCC or Clang is right to accept/reject this code, with respect to the standard - I can't find anything that would imply that _Atomic types can't be copied. It would seem that this would imply a bug in one of the two.Garnetgarnett
@AndrewHenle thank you for letting me know. I will keep this in mind for any code I write in the future.Garnetgarnett

© 2022 - 2024 — McMap. All rights reserved.