Skip to content

[C23] Disable diagnostic on struct defn in prototype #138516

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,10 @@ C23 Feature Support
- Implemented `WG14 N3037 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3037.pdf>`_
which allows tag types to be redefined within the same translation unit so
long as both definitions are structurally equivalent (same tag types, same
tag names, same tag members, etc).
tag names, same tag members, etc). As a result of this paper, ``-Wvisibility``
is no longer diagnosed in C23 if the parameter is a complete tag type (it
does still fire when the parameter is an incomplete tag type as that cannot
be completed).
- Fixed a failed assertion with an invalid parameter to the ``#embed``
directive. Fixes #GH126940.

Expand Down
10 changes: 8 additions & 2 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18348,7 +18348,10 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc,

// If we're declaring or defining a tag in function prototype scope in C,
// note that this type can only be used within the function and add it to
// the list of decls to inject into the function definition scope.
// the list of decls to inject into the function definition scope. However,
// in C23 and later, while the type is only visible within the function, the
// function can be called with a compatible type defined in the same TU, so
// we silence the diagnostic in C23 and up. This matches the behavior of GCC.
if ((Name || Kind == TagTypeKind::Enum) &&
getNonFieldDeclScope(S)->isFunctionPrototypeScope()) {
if (getLangOpts().CPlusPlus) {
Expand All @@ -18362,7 +18365,10 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc,
if (TUK == TagUseKind::Declaration)
Invalid = true;
} else if (!PrevDecl) {
Diag(Loc, diag::warn_decl_in_param_list) << Context.getTagDeclType(New);
// In C23 mode, if the declaration is complete, we do not want to
// diagnose.
if (!getLangOpts().C23 || TUK != TagUseKind::Definition)
Diag(Loc, diag::warn_decl_in_param_list) << Context.getTagDeclType(New);
}
}

Expand Down
3 changes: 1 addition & 2 deletions clang/test/C/C23/n3030.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,7 @@ static_assert(a == 1);
static_assert(b == 1);

void f1(enum a : long b); // expected-error {{non-defining declaration of enumeration with a fixed underlying type is only permitted as a standalone declaration; missing list of enumerators?}}
// expected-warning@-1 {{declaration of 'enum a' will not be visible outside of this function}}
void f2(enum c : long{x} d); // expected-warning {{declaration of 'enum c' will not be visible outside of this function}}
void f2(enum c : long{x} d);
enum e : int f3(); // expected-error {{non-defining declaration of enumeration with a fixed underlying type is only permitted as a standalone declaration; missing list of enumerators?}}

typedef enum t u; // expected-warning {{ISO C forbids forward references to 'enum' types}}
Expand Down
10 changes: 5 additions & 5 deletions clang/test/C/C23/n3037.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ void bar(void) {
#define PRODUCT(A ,B) struct prod { A a; B b; } // expected-note 2 {{expanded from macro 'PRODUCT'}}
#define SUM(A, B) struct sum { _Bool flag; union { A a; B b; }; } // expected-note 2 {{expanded from macro 'SUM'}}

void func1(PRODUCT(int, SUM(float, double)) x); // both-warning {{declaration of 'struct prod' will not be visible outside of this function}} \
both-warning {{declaration of 'struct sum' will not be visible outside of this function}} \
void func1(PRODUCT(int, SUM(float, double)) x); // c17-warning {{declaration of 'struct prod' will not be visible outside of this function}} \
c17-warning {{declaration of 'struct sum' will not be visible outside of this function}} \
c17-note {{passing argument to parameter 'x' here}}
void func2(PRODUCT(int, SUM(float, double)) y) { // both-warning {{declaration of 'struct prod' will not be visible outside of this function}} \
both-warning {{declaration of 'struct sum' will not be visible outside of this function}}
void func2(PRODUCT(int, SUM(float, double)) y) { // c17-warning {{declaration of 'struct prod' will not be visible outside of this function}} \
c17-warning {{declaration of 'struct sum' will not be visible outside of this function}}
func1(y); // c17-error {{passing 'struct prod' to parameter of incompatible type 'struct prod'}}
}

Expand Down Expand Up @@ -307,7 +307,7 @@ enum fixed_test_2 : typedef_of_type_int { FT2 }; // c17-error {{redefinition of
// Test more bizarre situations in terms of where the type is declared. This
// has always been allowed.
struct declared_funny_1 { int x; }
declared_funny_func(struct declared_funny_1 { int x; } arg) { // both-warning {{declaration of 'struct declared_funny_1' will not be visible outside of this function}}
declared_funny_func(struct declared_funny_1 { int x; } arg) { // c17-warning {{declaration of 'struct declared_funny_1' will not be visible outside of this function}}
return declared_funny_func((__typeof__(arg)){ 0 });
}

Expand Down
16 changes: 8 additions & 8 deletions clang/test/C/drs/dr0xx.c
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
/* RUN: %clang_cc1 -std=c89 -fsyntax-only -verify=expected,c89only -pedantic -Wno-declaration-after-statement -Wno-c11-extensions %s
RUN: %clang_cc1 -std=c89 -fsyntax-only -verify=expected,c89only -pedantic -Wno-declaration-after-statement -Wno-c11-extensions -fno-signed-char %s
RUN: %clang_cc1 -std=c99 -fsyntax-only -verify=expected,c99untilc2x -pedantic -Wno-c11-extensions %s
RUN: %clang_cc1 -std=c11 -fsyntax-only -verify=expected,c99untilc2x -pedantic %s
RUN: %clang_cc1 -std=c17 -fsyntax-only -verify=expected,c99untilc2x -pedantic %s
RUN: %clang_cc1 -std=c2x -fsyntax-only -verify=expected,c2xandup -pedantic %s
/* RUN: %clang_cc1 -std=c89 -fsyntax-only -verify=expected,c89only,c17andearlier -pedantic -Wno-declaration-after-statement -Wno-c11-extensions %s
RUN: %clang_cc1 -std=c89 -fsyntax-only -verify=expected,c89only,c17andearlier -pedantic -Wno-declaration-after-statement -Wno-c11-extensions -fno-signed-char %s
RUN: %clang_cc1 -std=c99 -fsyntax-only -verify=expected,c99untilc2x,c17andearlier -pedantic -Wno-c11-extensions %s
RUN: %clang_cc1 -std=c11 -fsyntax-only -verify=expected,c99untilc2x,c17andearlier -pedantic %s
RUN: %clang_cc1 -std=c17 -fsyntax-only -verify=expected,c99untilc2x,c17andearlier -pedantic %s
RUN: %clang_cc1 -std=c23 -fsyntax-only -verify=expected,c2xandup -pedantic %s
*/

/* The following are DRs which do not require tests to demonstrate
Expand Down Expand Up @@ -245,13 +245,13 @@ int dr032 = (1, 2); /* expected-warning {{left operand of comma operator has no
* Questions about definition of functions without a prototype
*/
void dr035_1(a, b) /* expected-warning {{a function definition without a prototype is deprecated in all versions of C and is not supported in C23}} */
int a(enum b {x, y}); /* expected-warning {{declaration of 'enum b' will not be visible outside of this function}} */
int a(enum b {x, y}); /* c17andearlier-warning {{declaration of 'enum b' will not be visible outside of this function}} */
int b; {
int test = x; /* expected-error {{use of undeclared identifier 'x'}} */
}

void dr035_2(c) /* expected-warning {{a function definition without a prototype is deprecated in all versions of C and is not supported in C23}} */
enum m{q, r} c; { /* expected-warning {{declaration of 'enum m' will not be visible outside of this function}} */
enum m{q, r} c; { /* c17andearlier-warning {{declaration of 'enum m' will not be visible outside of this function}} */
/* FIXME: This should be accepted because the scope of m, q, and r ends at
* the closing brace of the function per C89 6.1.2.1.
*/
Expand Down
8 changes: 4 additions & 4 deletions clang/test/C/drs/dr1xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -102,14 +102,14 @@ void dr102(void) {
* Formal parameters of incomplete type
*/
void dr103_1(int arg[]); /* ok, not an incomplete type due to rewrite */
void dr103_2(struct S s) {} /* expected-warning {{declaration of 'struct S' will not be visible outside of this function}}
void dr103_2(struct S s) {} /* untilc23-warning {{declaration of 'struct S' will not be visible outside of this function}}
expected-error {{variable has incomplete type 'struct S'}}
expected-note {{forward declaration of 'struct S'}} */
void dr103_3(struct S s); /* expected-warning {{declaration of 'struct S' will not be visible outside of this function}}
void dr103_3(struct S s); /* untilc23-warning {{declaration of 'struct S' will not be visible outside of this function}}
expected-note {{previous declaration is here}} */
void dr103_3(struct S { int a; } s) { } /* expected-warning {{declaration of 'struct S' will not be visible outside of this function}}
void dr103_3(struct S { int a; } s) { } /* untilc23-warning {{declaration of 'struct S' will not be visible outside of this function}}
expected-error {{conflicting types for 'dr103_3'}} */
void dr103_4(struct S s1, struct S { int a; } s2); /* expected-warning {{declaration of 'struct S' will not be visible outside of this function}} */
void dr103_4(struct S s1, struct S { int a; } s2); /* untilc23-warning {{declaration of 'struct S' will not be visible outside of this function}} */

/* WG14 DR105: dup 017
* Precedence of requirements on compatible types
Expand Down
21 changes: 21 additions & 0 deletions clang/test/Sema/c23-decl-in-prototype.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c23 %s
// RUN: %clang_cc1 -fsyntax-only -verify -std=c23 -Wvisibility %s

// In C23 mode, we only want to diagnose a declaration in a prototype if that
// declaration is for an incomplete tag type. Otherwise, we silence the
// diagnostic because the function could be called with a compatible type.

void f(struct Incomplete); // expected-warning {{will not be visible outside of this function}}
void g(struct Complete { int x; });

struct A {
struct B {
int j; // #j
} b;
};

void complicated(struct A { struct B { int j; } b; }); // Okay

void also_complicated(struct A { struct B { int glorx; } b; }); // expected-error {{type 'struct B' has incompatible definitions}} \
expected-note {{field has name 'glorx' here}} \
expected-note@#j {{field has name 'j' here}}
2 changes: 1 addition & 1 deletion clang/test/Sema/decl-in-prototype.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
// RUN: %clang_cc1 -fsyntax-only -verify -std=c17 %s

#define SA(n, c) int arr##n[(c) ? 1 : -1] = {}

Expand Down
2 changes: 1 addition & 1 deletion clang/test/Sema/enum.c
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ void PR8694(int* e) // expected-note {{passing argument to parameter 'e' here}}
{
}

void crash(enum E* e) // expected-warning {{declaration of 'enum E' will not be visible outside of this function}} \
void crash(enum E *e) // pre-c23-warning {{declaration of 'enum E' will not be visible outside of this function}} \
// expected-warning {{ISO C forbids forward references to 'enum' types}}
{
PR8694(e); // expected-warning {{incompatible pointer types passing 'enum E *' to parameter of type 'int *'}}
Expand Down
Loading