Skip to content

Correctly diagnose incomplete arrays with static storage in C #134374

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 2 commits into from
Apr 7, 2025

Conversation

AaronBallman
Copy link
Collaborator

A file scope declaration without an initializer which is neither extern nor thread_local is a tentative definition. If the declaration of an identifier for an object is a tentative definition and has internal linkage, the declared type shall not be an incomplete type.

Clang was previously failing to diagnose this in -pedantic mode.

Fixes #50661

A file scope declaration without an initializer which is neither extern
nor thread_local is a tentative definition. If the declaration of an
identifier for an object is a tentative definition and has internal
linkage, the declared type shall not be an incomplete type.

Clang was previously failing to diagnose this in -pedantic mode.

Fixes llvm#50661
@AaronBallman AaronBallman added clang Clang issues not falling into any other category c clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Apr 4, 2025
@llvmbot
Copy link
Member

llvmbot commented Apr 4, 2025

@llvm/pr-subscribers-clang

Author: Aaron Ballman (AaronBallman)

Changes

A file scope declaration without an initializer which is neither extern nor thread_local is a tentative definition. If the declaration of an identifier for an object is a tentative definition and has internal linkage, the declared type shall not be an incomplete type.

Clang was previously failing to diagnose this in -pedantic mode.

Fixes #50661


Full diff: https://github.com/llvm/llvm-project/pull/134374.diff

6 Files Affected:

  • (modified) clang/docs/ReleaseNotes.rst (+3)
  • (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+3-2)
  • (modified) clang/lib/Sema/SemaDecl.cpp (+4-2)
  • (modified) clang/test/C/drs/dr0xx.c (+3-1)
  • (modified) clang/test/Sema/incomplete-decl.c (+2-3)
  • (modified) clang/test/Sema/tentative-decls.c (+2-2)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 3055394dd8b6c..d913221f99a04 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -319,6 +319,9 @@ Improvements to Clang's diagnostics
 - ``-Wc++98-compat`` no longer diagnoses use of ``__auto_type`` or
   ``decltype(auto)`` as though it was the extension for ``auto``. (#GH47900)
 
+- Now correctly diagnose use of a tentative definition of an array with static
+  storage duration in pedantic mode in C. (#GH50661)
+
 Improvements to Clang's time-trace
 ----------------------------------
 
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 52dc477039129..bcb3ea5d04cd1 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -7346,8 +7346,9 @@ def err_typecheck_pointer_arith_void_type : Error<
   "arithmetic on%select{ a|}0 pointer%select{|s}0 to void">;
 def err_typecheck_decl_incomplete_type : Error<
   "variable has incomplete type %0">;
-def ext_typecheck_decl_incomplete_type : ExtWarn<
-  "tentative definition of variable with internal linkage has incomplete non-array type %0">,
+def ext_typecheck_decl_incomplete_type : Extension<
+  "tentative definition of variable with internal linkage has incomplete "
+  "%select{non-array|array}0 type %1">,
   InGroup<DiagGroup<"tentative-definition-incomplete-type">>;
 def err_tentative_def_incomplete_type : Error<
   "tentative definition has type %0 that is never completed">;
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 9b7b3f856cc55..35de4e8a47e18 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -14246,7 +14246,8 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
                   Var->getLocation(), ArrayT->getElementType(),
                   diag::err_array_incomplete_or_sizeless_type))
             Var->setInvalidDecl();
-        } else if (Var->getStorageClass() == SC_Static) {
+        }
+        if (Var->getStorageClass() == SC_Static) {
           // C99 6.9.2p3: If the declaration of an identifier for an object is
           // a tentative definition and has internal linkage (C99 6.2.2p3), the
           // declared type shall not be an incomplete type.
@@ -14258,7 +14259,8 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
           // NOTE: to avoid multiple warnings, only check the first declaration.
           if (Var->isFirstDecl())
             RequireCompleteType(Var->getLocation(), Type,
-                                diag::ext_typecheck_decl_incomplete_type);
+                                diag::ext_typecheck_decl_incomplete_type,
+                                Type->isArrayType());
         }
       }
 
diff --git a/clang/test/C/drs/dr0xx.c b/clang/test/C/drs/dr0xx.c
index 252dc9329c4ca..5fe023deaece9 100644
--- a/clang/test/C/drs/dr0xx.c
+++ b/clang/test/C/drs/dr0xx.c
@@ -139,7 +139,9 @@ int dr010_c = sizeof(dr010_t); /* expected-error {{invalid application of 'sizeo
  * Note: DR034 has a question resolved by DR011 and another question where the
  * result is UB.
  */
-static int dr011_a[]; /* expected-warning {{tentative array definition assumed to have one element}} */
+static int dr011_a[]; /* expected-warning {{tentative array definition assumed to have one element}}
+                         expected-warning {{tentative definition of variable with internal linkage has incomplete array type 'int[]'}}
+                       */
 void dr011(void) {
   extern int i[];
   {
diff --git a/clang/test/Sema/incomplete-decl.c b/clang/test/Sema/incomplete-decl.c
index bf2890bba9911..f8f234c6b7828 100644
--- a/clang/test/Sema/incomplete-decl.c
+++ b/clang/test/Sema/incomplete-decl.c
@@ -3,7 +3,7 @@
 
 
 
-struct foo; // c-note 5 {{forward declaration of 'struct foo'}} \
+struct foo; // c-note 4 {{forward declaration of 'struct foo'}} \
                cxx-note 3 {{forward declaration of 'foo'}}
 
 void b;  // expected-error {{variable has incomplete type 'void'}}
@@ -11,8 +11,7 @@ struct foo f; // c-error {{tentative definition has type 'struct foo' that is ne
                  cxx-error {{variable has incomplete type 'struct foo'}}
 
 static void c; // expected-error {{variable has incomplete type 'void'}}
-static struct foo g;  // c-warning {{tentative definition of variable with internal linkage has incomplete non-array type 'struct foo'}} \
-                         c-error {{tentative definition has type 'struct foo' that is never completed}} \
+static struct foo g;  // c-error {{tentative definition has type 'struct foo' that is never completed}} \
                          cxx-error {{variable has incomplete type 'struct foo'}}
 
 extern void d; // cxx-error {{variable has incomplete type 'void'}}
diff --git a/clang/test/Sema/tentative-decls.c b/clang/test/Sema/tentative-decls.c
index 713e65f3d9b35..94d21bdbf94da 100644
--- a/clang/test/Sema/tentative-decls.c
+++ b/clang/test/Sema/tentative-decls.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -fsyntax-only -Wprivate-extern -verify
+// RUN: %clang_cc1 %s -fsyntax-only -Wprivate-extern -pedantic -verify
 
 // PR3310
 struct a x1; // expected-note 2{{forward declaration of 'struct a'}}
@@ -58,7 +58,7 @@ void func2(void)
   extern double *p;
 }
 
-static int a0[];
+static int a0[]; // expected-warning {{tentative definition of variable with internal linkage has incomplete array type 'int[]'}}
 static int b0;
 
 static int a0[] = { 4 };

cxx-note 3 {{forward declaration of 'foo'}}

void b; // expected-error {{variable has incomplete type 'void'}}
struct foo f; // c-error {{tentative definition has type 'struct foo' that is never completed}} \
cxx-error {{variable has incomplete type 'struct foo'}}

static void c; // expected-error {{variable has incomplete type 'void'}}
static struct foo g; // c-warning {{tentative definition of variable with internal linkage has incomplete non-array type 'struct foo'}} \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did this one disappear?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because the diagnostic went from ExtWarn to Extension so it's no longer emitted by default. There's nothing dangerous about the tentative definition by itself, and we give other diagnostics in cases where it is an issue (tentative definition has type 'struct foo' that is never completed or tentative array definition assumed to have one element).

Co-authored-by: Mariya Podchishchaeva <[email protected]>
Copy link
Contributor

@Fznamznon Fznamznon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not super familiar with the affected area, but it looks good to me

@AaronBallman AaronBallman merged commit b9ec684 into llvm:main Apr 7, 2025
12 checks passed
@AaronBallman AaronBallman deleted the aballman-gh50661 branch April 7, 2025 11:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Incomplete array type with internal linkage: missing diagnostics under -pedantic
3 participants