Skip to content

[C] Allow __attribute__((nonstring)) on multidimensional arrays #138133

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

Conversation

AaronBallman
Copy link
Collaborator

This addresses post-commit review feedback from the Linux kernel folks and improves compatibility with the same feature in GCC

This addresses post-commit review feedback from the Linux kernel folks
and improves compatibility with the same feature in GCC
@AaronBallman AaronBallman added clang Clang issues not falling into any other category c clang:frontend Language frontend issues, e.g. anything involving "Sema" extension:gnu labels May 1, 2025
@llvmbot
Copy link
Member

llvmbot commented May 1, 2025

@llvm/pr-subscribers-clang

Author: Aaron Ballman (AaronBallman)

Changes

This addresses post-commit review feedback from the Linux kernel folks and improves compatibility with the same feature in GCC


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

2 Files Affected:

  • (modified) clang/lib/Sema/SemaInit.cpp (+15-2)
  • (modified) clang/test/Sema/attr-nonstring.c (+79-1)
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 6900ccb11c3db..5bdf62e0c4e0d 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -261,8 +261,21 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, const ArrayType *AT,
           << Str->getSourceRange();
     else if (StrLength - 1 == ArrayLen) {
       // If the entity being initialized has the nonstring attribute, then
-      // silence the "missing nonstring" diagnostic.
-      if (const ValueDecl *D = Entity.getDecl();
+      // silence the "missing nonstring" diagnostic. If there's no entity,
+      // check whether we're initializing an array of arrays; if so, walk the
+      // parents to find an entity.
+      auto FindCorrectEntity = [](const InitializedEntity &Entity) {
+        const ValueDecl *Ret = nullptr;
+        for (const InitializedEntity *E = &Entity; E; E = Entity.getParent()) {
+          Ret = E->getDecl();
+          if (Ret)
+            break;
+          if (!E->getType()->isArrayType())
+            break;
+        }
+        return Ret;
+      };
+      if (const ValueDecl *D = FindCorrectEntity(Entity);
           !D || !D->hasAttr<NonStringAttr>())
         S.Diag(
             Str->getBeginLoc(),
diff --git a/clang/test/Sema/attr-nonstring.c b/clang/test/Sema/attr-nonstring.c
index 31728e701a3fc..99520c8890500 100644
--- a/clang/test/Sema/attr-nonstring.c
+++ b/clang/test/Sema/attr-nonstring.c
@@ -2,7 +2,7 @@
 // RUN: %clang_cc1 -fsyntax-only -verify=noncxx,expected,no-nonstring -Wextra %s
 // RUN: %clang_cc1 -fsyntax-only -verify=noncxx,expected,compat -Wc++-unterminated-string-initialization %s
 // RUN: %clang_cc1 -fsyntax-only -verify=noncxx,expected,compat -Wc++-compat %s
-// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx -x c++ %s
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx -x c++ -Wno-c99-designator %s
 // RUN: %clang_cc1 -fsyntax-only -verify=expected,noncxx -Wno-unterminated-string-initialization %s
 // RUN: %clang_cc1 -fsyntax-only -verify=expected,noncxx -Wc++-compat -Wextra -Wno-unterminated-string-initialization -Wno-c++-unterminated-string-initialization %s
 
@@ -39,3 +39,81 @@ __attribute__((nonstring)) int eek2;              // expected-warning {{'nonstri
 // diagnostic when you overwrite more than just the null terminator.
 char too_big[3] = "this is too big"; // noncxx-warning {{initializer-string for char array is too long}} \
                                         cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 16 (including the null terminating character)}}
+
+// Show that this also applies to arrays of objects containing strings, too.
+const char md_array[][3] __attribute__((nonstring)) = { "BAR", "FOO", };   // compat-warning 2 {{initializer-string for character array is too long for C++, array size is 3 but initializer has size 4 (including the null terminating character)}} \
+                                                                              cxx-error 2 {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
+
+struct StructWithNSArray {
+  __attribute__((nonstring)) char blech[3];
+};
+
+struct StructWithNSArray s1[] = {
+  { "FOO" }, // compat-warning {{initializer-string for character array is too long for C++, array size is 3 but initializer has size 4 (including the null terminating character)}} \
+                cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
+  { "BAR" }  // compat-warning {{initializer-string for character array is too long for C++, array size is 3 but initializer has size 4 (including the null terminating character)}} \
+                cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
+};
+
+struct T1 {
+  struct StructWithNSArray s[2];
+};
+struct U1 {
+  struct T1 t[2];
+};
+struct U1 u[] = {
+  {
+    .t[0] = {
+      .s[0] = { "FOO" }, // compat-warning {{initializer-string for character array is too long for C++, array size is 3 but initializer has size 4 (including the null terminating character)}} \
+                            cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
+      .s[1] = { "BAR" }  // compat-warning {{initializer-string for character array is too long for C++, array size is 3 but initializer has size 4 (including the null terminating character)}} \
+                            cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
+    },
+    .t[1] = {
+      .s[0] = { "BIP" }, // compat-warning {{initializer-string for character array is too long for C++, array size is 3 but initializer has size 4 (including the null terminating character)}} \
+                            cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
+      .s[1] = { "BOP" }  // compat-warning {{initializer-string for character array is too long for C++, array size is 3 but initializer has size 4 (including the null terminating character)}} \
+                            cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
+    }
+  }
+};
+
+struct StructWithoutNSArray {
+  char blech[3];
+};
+
+struct StructWithoutNSArray s2[] = {
+  { "FOO" }, // no-nonstring-warning {{initializer-string for character array is too long, array size is 3 but initializer has size 4 (including the null terminating character); did you mean to use the 'nonstring' attribute?}} \
+                compat-warning {{initializer-string for character array is too long for C++, array size is 3 but initializer has size 4 (including the null terminating character)}} \
+                            cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
+  { "BAR" } // no-nonstring-warning {{initializer-string for character array is too long, array size is 3 but initializer has size 4 (including the null terminating character); did you mean to use the 'nonstring' attribute?}} \
+               compat-warning {{initializer-string for character array is too long for C++, array size is 3 but initializer has size 4 (including the null terminating character)}} \
+               cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
+};
+
+struct T2 {
+  struct StructWithoutNSArray s[2];
+};
+struct U2 {
+  struct T2 t[2];
+};
+struct U2 u2[] = {
+  {
+    .t[0] = {
+      .s[0] = { "FOO" }, // no-nonstring-warning {{initializer-string for character array is too long, array size is 3 but initializer has size 4 (including the null terminating character); did you mean to use the 'nonstring' attribute?}} \
+                            compat-warning {{initializer-string for character array is too long for C++, array size is 3 but initializer has size 4 (including the null terminating character)}} \
+                            cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
+      .s[1] = { "BAR" }  // no-nonstring-warning {{initializer-string for character array is too long, array size is 3 but initializer has size 4 (including the null terminating character); did you mean to use the 'nonstring' attribute?}} \
+                            compat-warning {{initializer-string for character array is too long for C++, array size is 3 but initializer has size 4 (including the null terminating character)}} \
+                            cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
+    },
+    .t[1] = {
+      .s[0] = { "BIP" }, // no-nonstring-warning {{initializer-string for character array is too long, array size is 3 but initializer has size 4 (including the null terminating character); did you mean to use the 'nonstring' attribute?}} \
+                            compat-warning {{initializer-string for character array is too long for C++, array size is 3 but initializer has size 4 (including the null terminating character)}} \
+                            cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
+      .s[1] = { "BOP" }  // no-nonstring-warning {{initializer-string for character array is too long, array size is 3 but initializer has size 4 (including the null terminating character); did you mean to use the 'nonstring' attribute?}} \
+                            compat-warning {{initializer-string for character array is too long for C++, array size is 3 but initializer has size 4 (including the null terminating character)}} \
+                            cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
+    }
+  }
+};

Copy link
Member

@nathanchance nathanchance left a comment

Choose a reason for hiding this comment

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

Thanks, this appears to resolve the warning in the one place that I know needs it.

@AaronBallman AaronBallman merged commit 3d4f979 into llvm:main May 2, 2025
11 checks passed
@AaronBallman AaronBallman deleted the aballman-attr-nonstring-updates branch May 2, 2025 11:19
IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
…#138133)

This addresses post-commit review feedback from the Linux kernel folks
and improves compatibility with the same feature in GCC
IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
…#138133)

This addresses post-commit review feedback from the Linux kernel folks
and improves compatibility with the same feature in GCC
IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
…#138133)

This addresses post-commit review feedback from the Linux kernel folks
and improves compatibility with the same feature in GCC
GeorgeARM pushed a commit to GeorgeARM/llvm-project that referenced this pull request May 7, 2025
…#138133)

This addresses post-commit review feedback from the Linux kernel folks
and improves compatibility with the same feature in GCC
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 extension:gnu
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants