Created attachment 59117 [details] tag-compat-pointer-bug.i C23 changed struct tag compatibility rules to allow for structs with the same tag and multiple non-conflicting definitions to be compatible, and for incomplete types to be defined and established as compatible later in the translation unit. However, when the attached code attempts to use such an incomplete type for a function, the compiler instead gives the familiar pre-C23 error about incompatible types (i.e., "struct foo *" vs "struct foo *"). A forward declaration at the start (i.e., struct_foo;) and/or an inline definition of the struct within the function signature (i.e., void bar(struct foo {int value;} *foo) {}) allow the code to compile without issues, but in their absence it breaks. Note that this issue has a lot more potential subtlety with language lawyer standardese than it may seem at first, but I'm 95% sure that tag compatibility is supposed to allow for code like the attached to work now. See the below for additional reproducibility information. `uname -a`: Linux votocon 4.19.0-21-amd64 #1 SMP Debian 4.19.249-2 (2022-06-30) x86_64 GNU/Linux `lsb_release -a`: Distributor ID: Devuan Description: Devuan GNU/Linux 5 (daedalus) Release: 5 Codename: daedalus gcc configure options: ../../configure --prefix=/opt/gcc/14.2.0 --enable-lto compiler command/options: gcc --std=c23 tag-compat-pointer-bug.c
This may possibly have some connections to the behaviour seen in PR116726.
This may not actually be about pointer issues specifically - I came across another failing test case that I think is most likely caused by the same underlying issue: typedef void f(struct s1); struct s1 { int f1; }; typedef void f(struct s1);
Thank you. I think I have identified this issue already. I will submit a patch soon.
Although the new example doesn't crash and the error I get seems correct to me. What is the problem you see here?
Sorry, mixed this up with the other bug. Here I would say the behavior is correct as specified in ISO C23. Note that incomplete structs could be completed later also before ISO C23. But incomplete struct types are incompatible to other struct types with the same tag, and the incomplete struct declared in prototype scope is therefor incompatible to the completed one. If you have a forward declaration so that the struct in the function prototype refers to a file scope version that is completed later, it works. https://godbolt.org/z/qPKcvGevM Of course, whether the languages are perfect as specified is a different question. With "typedef" there is the additional issue that "typedef" currently allows redefinition only for identical types, not merely compatible types.
I was pretty sure the first example in the attachment to this PR was something that should work (less so about the second), though something something standardese something something language lawyers. Especially to one that doesn't even have the final spec when various subtleties were under frequent refinement, it can be hard to know what's supposed to be valid. I remember seeing some stuff suggesting that the rules would be different if it was something completed in the same vs a different translation unit, for instance, and I'm just a passerby to the spec. Your point about whether the spec is perfect is well understood, but that's what c2y/c2z/hopes/dreams are for, and what matters here is just what the spec states rather than what it "should". That being said, I'm normally rigid about forward declaring *everything* even when the definition is literally one line further down (don't judge!), so now I'm kinda wondering if there may have been a cvise reduction issue here.
Your comment about typedefs is just starting to sink in...I'll have to return to this later though, as this is a conference week for me and it's about to start up again soon.