https://github.com/AaronBallman updated 
https://github.com/llvm/llvm-project/pull/140578

>From 625662da41256345c4609835754c3a61018b54ca Mon Sep 17 00:00:00 2001
From: Aaron Ballman <aa...@aaronballman.com>
Date: Mon, 19 May 2025 13:09:03 -0400
Subject: [PATCH 1/2] [C] Do not diagnose flexible array members with
 -Wdefault-const-init-field-unsafe

This addresses post-commit review feedback from someone who discovered
that we diagnosed code like the following:

  struct S {
    int len;
    const char fam[];
  } s;

despite it being invalid to initialize the flexible array member.

Note, this applies to flexible array members and zero-sized arrays at
the end of a structure (an old-style flexible array member), but it
does not apply to one-sized arrays at the end of a structure because
those do occupy storage that can be initialized.
---
 clang/lib/Sema/SemaInit.cpp               |  8 ++++++
 clang/test/Sema/warn-default-const-init.c | 30 +++++++++++++++++++++++
 2 files changed, 38 insertions(+)

diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 9ee8603ff7811..e17e68966dc00 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -6513,6 +6513,14 @@ static bool canPerformArrayCopy(const InitializedEntity 
&Entity) {
 static const FieldDecl *getConstField(const RecordDecl *RD) {
   assert(!isa<CXXRecordDecl>(RD) && "Only expect to call this in C mode");
   for (const FieldDecl *FD : RD->fields()) {
+    // If the field is a flexible array member, we don't want to consider it
+    // as a const field because there's no way to initialize the FAM anyway.
+    if (Decl::isFlexibleArrayMemberLike(
+            FD->getASTContext(), FD, FD->getType(),
+            LangOptions::StrictFlexArraysLevelKind::ZeroOrIncomplete,
+            /*IgnoreTemplateOrMacroSubstitution=*/true))
+      continue;
+
     QualType QT = FD->getType();
     if (QT.isConstQualified())
       return FD;
diff --git a/clang/test/Sema/warn-default-const-init.c 
b/clang/test/Sema/warn-default-const-init.c
index e788d72899685..e6ff0aa783e23 100644
--- a/clang/test/Sema/warn-default-const-init.c
+++ b/clang/test/Sema/warn-default-const-init.c
@@ -85,3 +85,33 @@ void func() {
   static const int b; // zero-init-var-warning {{default initialization of an 
object of type 'const int' is incompatible with C++}} \
                          cxx-error {{default initialization of an object of 
const type 'const int'}}
 }
+
+// Test the behavior of flexible array members. Those cannot be initialized
+// when a stack-allocated object of the structure type is created. We handle
+// degenerate flexible arrays similarly, but only if the array does not
+// actually specify any storage. Note that C++ does not have flexible array
+// members at all, which is why the test is disabled there.
+#ifndef __cplusplus
+struct RealFAM {
+  int len;
+  const char fam[];
+};
+
+struct FakeFAM {
+  int len;
+  const char fam[0];
+};
+
+struct NotTreatedAsAFAM {
+  int len;
+  const char fam[1];              // unsafe-field-note {{member 'fam' declared 
'const' here}} \
+                                     unsafe-field-compat-note {{member 'fam' 
declared 'const' here}}
+};
+
+void test_fams() {
+  struct RealFAM One;
+  struct FakeFAM Two;
+  struct NotTreatedAsAFAM Three;  // unsafe-field-warning {{default 
initialization of an object of type 'struct NotTreatedAsAFAM' with const member 
leaves the object uninitialized}} \
+                                     unsafe-field-compat-warning {{default 
initialization of an object of type 'struct NotTreatedAsAFAM' with const member 
leaves the object uninitialized and is incompatible with C++}}
+}
+#endif // !defined(__cplusplus)

>From 2637a020d818a205d3be933f73f1449a0870faf0 Mon Sep 17 00:00:00 2001
From: Aaron Ballman <aa...@aaronballman.com>
Date: Tue, 20 May 2025 08:22:19 -0400
Subject: [PATCH 2/2] Base behavior on -fstrict-flex-arrays

---
 clang/lib/Sema/SemaInit.cpp               |  5 +++--
 clang/test/Sema/warn-default-const-init.c | 23 +++++++++++++----------
 2 files changed, 16 insertions(+), 12 deletions(-)

diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index e17e68966dc00..ddadfa0ac3490 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -6515,9 +6515,10 @@ static const FieldDecl *getConstField(const RecordDecl 
*RD) {
   for (const FieldDecl *FD : RD->fields()) {
     // If the field is a flexible array member, we don't want to consider it
     // as a const field because there's no way to initialize the FAM anyway.
+    const ASTContext &Ctx = FD->getASTContext();
     if (Decl::isFlexibleArrayMemberLike(
-            FD->getASTContext(), FD, FD->getType(),
-            LangOptions::StrictFlexArraysLevelKind::ZeroOrIncomplete,
+            Ctx, FD, FD->getType(),
+            Ctx.getLangOpts().getStrictFlexArraysLevel(),
             /*IgnoreTemplateOrMacroSubstitution=*/true))
       continue;
 
diff --git a/clang/test/Sema/warn-default-const-init.c 
b/clang/test/Sema/warn-default-const-init.c
index e6ff0aa783e23..a70a0ccb6ebc6 100644
--- a/clang/test/Sema/warn-default-const-init.c
+++ b/clang/test/Sema/warn-default-const-init.c
@@ -1,23 +1,26 @@
 // Both of these should enable everything.
-// RUN: %clang_cc1 -fsyntax-only 
-verify=unsafe-var-compat,unsafe-field-compat,zero-init-var,zero-init-field 
-Wc++-compat -Wno-tentative-definition-compat %s
-// RUN: %clang_cc1 -fsyntax-only 
-verify=unsafe-var,unsafe-field,zero-init-var,zero-init-field 
-Wdefault-const-init %s
+// RUN: %clang_cc1 -fsyntax-only 
-verify=unsafe-var-compat,unsafe-field-compat,zero-init-var,zero-init-field 
-Wc++-compat -Wno-tentative-definition-compat -fstrict-flex-arrays=2 %s
+// RUN: %clang_cc1 -fsyntax-only 
-verify=unsafe-var,unsafe-field,zero-init-var,zero-init-field,unsafe-field-restricted-flex
 -Wdefault-const-init -fstrict-flex-arrays=2 %s
 
 // This should enable nothing.
 // RUN: %clang_cc1 -fsyntax-only -verify=good -Wno-default-const-init-unsafe %s
 
 // Only unsafe field and variable diagnostics
-// RUN: %clang_cc1 -fsyntax-only -verify=unsafe-var,unsafe-field %s
-// RUN: %clang_cc1 -fsyntax-only -verify=unsafe-var,unsafe-field 
-Wdefault-const-init-unsafe %s
+// RUN: %clang_cc1 -fsyntax-only 
-verify=unsafe-var,unsafe-field,unsafe-field-restricted-flex 
-fstrict-flex-arrays=2 %s
+// RUN: %clang_cc1 -fsyntax-only 
-verify=unsafe-var,unsafe-field,unsafe-field-restricted-flex 
-Wdefault-const-init-unsafe -fstrict-flex-arrays=2 %s
 
 // Only zero init field and variable diagnostics
 // RUN: %clang_cc1 -fsyntax-only -verify=zero-init-var,zero-init-field 
-Wdefault-const-init -Wno-default-const-init-unsafe %s
 
 // Only zero init and unsafe field diagnostics
-// RUN: %clang_cc1 -fsyntax-only -verify=zero-init-field,unsafe-field 
-Wno-default-const-init-var-unsafe -Wdefault-const-init-field %s
+// RUN: %clang_cc1 -fsyntax-only 
-verify=zero-init-field,unsafe-field,unsafe-field-restricted-flex 
-Wno-default-const-init-var-unsafe -Wdefault-const-init-field 
-fstrict-flex-arrays=2 %s
 
 // Only zero init and unsafe variable diagnostics
 // RUN: %clang_cc1 -fsyntax-only -verify=zero-init-var,unsafe-var 
-Wno-default-const-init-field-unsafe -Wdefault-const-init-var %s
 
+// Only unsafe field diagnostics, but with flexible arrays set to any kind of 
array
+// RUN: %clang_cc1 -fsyntax-only -verify=unsafe-field 
-Wno-default-const-init-var-unsafe -Wdefault-const-init-field-unsafe 
-fstrict-flex-arrays=0 %s
+
 // C++ tests
 // RUN: %clang_cc1 -fsyntax-only -verify=cxx -x c++ %s
 
@@ -88,9 +91,9 @@ void func() {
 
 // Test the behavior of flexible array members. Those cannot be initialized
 // when a stack-allocated object of the structure type is created. We handle
-// degenerate flexible arrays similarly, but only if the array does not
-// actually specify any storage. Note that C++ does not have flexible array
-// members at all, which is why the test is disabled there.
+// degenerate flexible arrays based on -fstrict-flex-arrays. Note that C++ does
+// not have flexible array members at all, which is why the test is disabled
+// there.
 #ifndef __cplusplus
 struct RealFAM {
   int len;
@@ -104,14 +107,14 @@ struct FakeFAM {
 
 struct NotTreatedAsAFAM {
   int len;
-  const char fam[1];              // unsafe-field-note {{member 'fam' declared 
'const' here}} \
+  const char fam[1];              // unsafe-field-restricted-flex-note 
{{member 'fam' declared 'const' here}} \
                                      unsafe-field-compat-note {{member 'fam' 
declared 'const' here}}
 };
 
 void test_fams() {
   struct RealFAM One;
   struct FakeFAM Two;
-  struct NotTreatedAsAFAM Three;  // unsafe-field-warning {{default 
initialization of an object of type 'struct NotTreatedAsAFAM' with const member 
leaves the object uninitialized}} \
+  struct NotTreatedAsAFAM Three;  // unsafe-field-restricted-flex-warning 
{{default initialization of an object of type 'struct NotTreatedAsAFAM' with 
const member leaves the object uninitialized}} \
                                      unsafe-field-compat-warning {{default 
initialization of an object of type 'struct NotTreatedAsAFAM' with const member 
leaves the object uninitialized and is incompatible with C++}}
 }
 #endif // !defined(__cplusplus)

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to