Bug 116728 - c23 tag compatibility broken with pointers to incomplete types
Summary: c23 tag compatibility broken with pointers to incomplete types
Status: UNCONFIRMED
Alias: None
Product: gcc
Classification: Unclassified
Component: c (show other bugs)
Version: 14.2.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2024-09-15 21:28 UTC by Hime Haieto
Modified: 2024-09-18 16:47 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments
tag-compat-pointer-bug.i (175 bytes, text/plain)
2024-09-15 21:28 UTC, Hime Haieto
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Hime Haieto 2024-09-15 21:28:48 UTC
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
Comment 1 Hime Haieto 2024-09-15 23:45:08 UTC
This may possibly have some connections to the behaviour seen in PR116726.
Comment 2 Hime Haieto 2024-09-17 01:02:32 UTC
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);
Comment 3 Martin Uecker 2024-09-17 05:43:07 UTC
Thank you. I think I have identified this issue already. I will submit a patch soon.
Comment 4 Martin Uecker 2024-09-17 08:40:45 UTC
Although the new example doesn't crash and the error I get seems correct to me. What is the problem you see here?
Comment 5 Martin Uecker 2024-09-17 09:35:44 UTC
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.
Comment 6 Hime Haieto 2024-09-17 11:10:17 UTC
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.
Comment 7 Hime Haieto 2024-09-17 11:14:02 UTC
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.