[clang] 00f9ef2 - [C] Modify -Wdefault-const-init (#137961)

via cfe-commits cfe-commits at lists.llvm.org
Thu May 1 04:08:09 PDT 2025


Author: Aaron Ballman
Date: 2025-05-01T07:08:06-04:00
New Revision: 00f9ef282c7482754a0fea497417604d1deca9fa

URL: https://github.com/llvm/llvm-project/commit/00f9ef282c7482754a0fea497417604d1deca9fa
DIFF: https://github.com/llvm/llvm-project/commit/00f9ef282c7482754a0fea497417604d1deca9fa.diff

LOG: [C] Modify -Wdefault-const-init (#137961)

Post-commit review feedback on
https://github.com/llvm/llvm-project/pull/137166 raised a concern from
the Linux kernel about wanting to silence the new diagnostic when the
uninitialized object is a const member of a structure. These members can
be initialized later if the containing object is non-const, such as
through a call to memset, for example.

This splits the diagnostic groups into:
```
-Wc++-compat
  -Wdefault-const-init
    -Wdefault-const-init-field
    -Wdefault-const-init-var
    -Wdefault-const-init-unsafe
      -Wdefault-const-init-field-unsafe
      -Wdefault-const-init-var-unsafe
```

---------

Co-authored-by: Mariya Podchishchaeva <mariya.podchishchaeva at intel.com>

Added: 
    

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/include/clang/Basic/DiagnosticGroups.td
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/lib/Sema/Sema.cpp
    clang/lib/Sema/SemaDecl.cpp
    clang/lib/Sema/SemaInit.cpp
    clang/test/Sema/warn-default-const-init.c

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 68ca6aa6bc49d..65ae5945ca27c 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -141,12 +141,16 @@ C Language Changes
   function type in Microsoft compatibility mode. #GH124869
 - Clang now allows ``restrict`` qualifier for array types with pointer elements (#GH92847).
 - Clang now diagnoses ``const``-qualified object definitions without an
-  initializer. If the object is zero-initialized, it will be diagnosed under
-  the new warning ``-Wdefault-const-init`` (which is grouped under
-  ``-Wc++-compat`` because this construct is not compatible with C++). If the
-  object is left uninitialized, it will be diagnosed unsed the new warning
-  ``-Wdefault-const-init-unsafe`` (which is grouped under
-  ``-Wdefault-const-init``). #GH19297
+  initializer. If the object is a variable or field which is zero-initialized,
+  it will be diagnosed under the new warning ``-Wdefault-const-init-var`` or
+  ``-Wdefault-const-init-field``, respectively. Similarly, if the variable or
+  field is not zero-initialized, it will be diagnosed under the new diagnostic
+  ``-Wdefault-const-init-var-unsafe`` or ``-Wdefault-const-init-field-unsafe``,
+  respectively. The unsafe diagnostic variants are grouped under a new
+  diagnostic ``-Wdefault-const-init-unsafe``, which itself is grouped under the
+  new diagnostic ``-Wdefault-const-init``. Finally, ``-Wdefault-const-init`` is
+  grouped under ``-Wc++-compat`` because these constructs are not compatible
+  with C++. #GH19297
 - Added ``-Wimplicit-void-ptr-cast``, grouped under ``-Wc++-compat``, which
   diagnoses implicit conversion from ``void *`` to another pointer type as
   being incompatible with C++. (#GH17792)

diff  --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td
index de3374962c6b0..21d5d54e9c8c5 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -163,8 +163,16 @@ def InitStringTooLongMissingNonString :
 def InitStringTooLongForCpp :
   DiagGroup<"c++-unterminated-string-initialization">;
 def HiddenCppDecl : DiagGroup<"c++-hidden-decl">;
-def DefaultConstInitUnsafe : DiagGroup<"default-const-init-unsafe">;
-def DefaultConstInit : DiagGroup<"default-const-init", [DefaultConstInitUnsafe]>;
+def DefaultConstInitFieldUnsafe : DiagGroup<"default-const-init-field-unsafe">;
+def DefaultConstInitVarUnsafe : DiagGroup<"default-const-init-var-unsafe">;
+def DefaultConstInitUnsafe : DiagGroup<"default-const-init-unsafe",
+                                       [DefaultConstInitFieldUnsafe,
+                                        DefaultConstInitVarUnsafe]>;
+def DefaultConstInitField : DiagGroup<"default-const-init-field">;
+def DefaultConstInitVar : DiagGroup<"default-const-init-var">;
+def DefaultConstInit : DiagGroup<"default-const-init",
+                                 [DefaultConstInitField, DefaultConstInitVar,
+                                  DefaultConstInitUnsafe]>;
 def ImplicitVoidPtrCast : DiagGroup<"implicit-void-ptr-cast">;
 def ImplicitIntToEnumCast : DiagGroup<"implicit-int-enum-cast",
                                       [ImplicitEnumEnumCast]>;

diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 823d4bb687497..c6c52f471479e 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -8218,14 +8218,20 @@ def err_address_space_qualified_delete : Error<
 
 def note_default_init_const_member : Note<
   "member %0 declared 'const' here">;
+def warn_default_init_const_field : Warning<
+  "default initialization of an object of type %0 with const member is "
+  "incompatible with C++">, InGroup<DefaultConstInitField>, DefaultIgnore;
 def warn_default_init_const : Warning<
-  "default initialization of an object of type %0%select{| with const member}1 "
-  "is incompatible with C++">,
-  InGroup<DefaultConstInit>, DefaultIgnore;
+  "default initialization of an object of type %0 is incompatible with C++">,
+  InGroup<DefaultConstInitVar>, DefaultIgnore;
+def warn_default_init_const_field_unsafe : Warning<
+  "default initialization of an object of type %0 with const member leaves the "
+  "object uninitialized and is incompatible with C++">,
+  InGroup<DefaultConstInitFieldUnsafe>;
 def warn_default_init_const_unsafe : Warning<
-  "default initialization of an object of type %0%select{| with const member}1 "
-  "leaves the object uninitialized and is incompatible with C++">,
-  InGroup<DefaultConstInitUnsafe>;
+  "default initialization of an object of type %0 leaves the object "
+  "uninitialized and is incompatible with C++">,
+  InGroup<DefaultConstInitVarUnsafe>;
 def err_default_init_const : Error<
   "default initialization of an object of const type %0"
   "%select{| without a user-provided default constructor}1">;

diff  --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 4edcd3f945f6c..39e370a03afd0 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -1457,7 +1457,7 @@ void Sema::ActOnEndOfTranslationUnit() {
       if (VD->getStorageDuration() == SD_Static ||
           VD->getStorageDuration() == SD_Thread)
         DiagID = diag::warn_default_init_const;
-      Diag(VD->getLocation(), DiagID) << Type << /*not a field*/ 0;
+      Diag(VD->getLocation(), DiagID) << Type;
     }
 
     // Notify the consumer that we've completed a tentative definition.

diff  --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 56396cddf57b8..25ee19e0ba5f1 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -14348,7 +14348,7 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
       if (Var->getStorageDuration() == SD_Static ||
           Var->getStorageDuration() == SD_Thread)
         DiagID = diag::warn_default_init_const;
-      Diag(Var->getLocation(), DiagID) << Type << /*not a field*/ 0;
+      Diag(Var->getLocation(), DiagID) << Type;
     }
 
     // Check for jumps past the implicit initializer.  C++0x

diff  --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 34766fd87af33..6900ccb11c3db 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -6607,12 +6607,12 @@ void InitializationSequence::InitializeFrom(Sema &S,
       // initializer present.
       if (!Initializer) {
         if (const FieldDecl *FD = getConstField(Rec)) {
-          unsigned DiagID = diag::warn_default_init_const_unsafe;
+          unsigned DiagID = diag::warn_default_init_const_field_unsafe;
           if (Var->getStorageDuration() == SD_Static ||
               Var->getStorageDuration() == SD_Thread)
-            DiagID = diag::warn_default_init_const;
+            DiagID = diag::warn_default_init_const_field;
 
-          S.Diag(Var->getLocation(), DiagID) << Var->getType() << /*member*/ 1;
+          S.Diag(Var->getLocation(), DiagID) << Var->getType();
           S.Diag(FD->getLocation(), diag::note_default_init_const_member) << FD;
         }
       }

diff  --git a/clang/test/Sema/warn-default-const-init.c b/clang/test/Sema/warn-default-const-init.c
index b8da41b333f3d..b6c593e578bd5 100644
--- a/clang/test/Sema/warn-default-const-init.c
+++ b/clang/test/Sema/warn-default-const-init.c
@@ -1,28 +1,22 @@
-// RUN: %clang_cc1 -fsyntax-only -verify=c,unsafe -Wdefault-const-init %s
-// RUN: %clang_cc1 -fsyntax-only -verify=c,unsafe -Wc++-compat %s
-// RUN: %clang_cc1 -fsyntax-only -verify=unsafe %s
-// RUN: %clang_cc1 -fsyntax-only -verify=c -Wdefault-const-init -Wno-default-const-init-unsafe %s
-// RUN: %clang_cc1 -fsyntax-only -verify=good -Wno-default-const-init-unsafe %s
-// RUN: %clang_cc1 -fsyntax-only -verify=cxx -x c++ %s
-// good-no-diagnostics
+// RUN: %clang_cc1 -fsyntax-only -verify=unsafe-var,unsafe-field -Wdefault-const-init-unsafe %s
 
 struct A { int i; };
-struct S{ const int i; };              // unsafe-note 2 {{member 'i' declared 'const' here}} \
+struct S{ const int i; };              // unsafe-field-note 2 {{member 'i' declared 'const' here}} \
                                           cxx-note 3 {{default constructor of 'S' is implicitly deleted because field 'i' of const-qualified type 'const int' would not be initialized}}
 struct T { struct S s; };              // cxx-note {{default constructor of 'T' is implicitly deleted because field 's' has a deleted default constructor}}
 struct U { struct S s; const int j; };
-struct V { int i; const struct A a; }; // unsafe-note {{member 'a' declared 'const' here}} \
+struct V { int i; const struct A a; }; // unsafe-field-note {{member 'a' declared 'const' here}} \
                                           cxx-note {{default constructor of 'V' is implicitly deleted because field 'a' of const-qualified type 'const struct A' would not be initialized}}
-struct W { struct A a; const int j; }; // unsafe-note {{member 'j' declared 'const' here}} \
+struct W { struct A a; const int j; }; // unsafe-field-note {{member 'j' declared 'const' here}} \
                                           cxx-note {{default constructor of 'W' is implicitly deleted because field 'j' of const-qualified type 'const int' would not be initialized}}
 
 void f() {
-  struct S s1; // unsafe-warning {{default initialization of an object of type 'struct S' with const member leaves the object uninitialized and is incompatible with C++}} \
+  struct S s1; // unsafe-field-warning {{default initialization of an object of type 'struct S' with const member leaves the object uninitialized and is incompatible with C++}} \
                   cxx-error {{call to implicitly-deleted default constructor of 'struct S'}}
   struct S s2 = { 0 };
 }
 void g() {
-  struct T t1; // unsafe-warning {{default initialization of an object of type 'struct T' with const member leaves the object uninitialized and is incompatible with C++}} \
+  struct T t1; // unsafe-field-warning {{default initialization of an object of type 'struct T' with const member leaves the object uninitialized and is incompatible with C++}} \
                   cxx-error {{call to implicitly-deleted default constructor of 'struct T'}}
   struct T t2 = { { 0 } };
 }
@@ -31,13 +25,13 @@ void h() {
   struct U u2 = { { 0 }, 0 };
 }
 void x() {
-  struct V v1; // unsafe-warning {{default initialization of an object of type 'struct V' with const member leaves the object uninitialized and is incompatible with C++}} \
+  struct V v1; // unsafe-field-warning {{default initialization of an object of type 'struct V' with const member leaves the object uninitialized and is incompatible with C++}} \
                   cxx-error {{call to implicitly-deleted default constructor of 'struct V'}}
   struct V v2 = { 0 };
   struct V v3 = { 0, { 0 } };
 }
 void y() {
-  struct W w1; // unsafe-warning {{default initialization of an object of type 'struct W' with const member leaves the object uninitialized and is incompatible with C++}} \
+  struct W w1; // unsafe-field-warning {{default initialization of an object of type 'struct W' with const member leaves the object uninitialized and is incompatible with C++}} \
                   cxx-error {{call to implicitly-deleted default constructor of 'struct W'}}
   struct W w2 = { 0 };
   struct W w3 = { { 0 }, 0 };
@@ -47,17 +41,17 @@ void y() {
 extern const int i;
 const int i = 12;
 
-static const int j; // c-warning {{default initialization of an object of type 'const int' is incompatible with C++}} \
+static const int j; // 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'}}
-const int k;        // c-warning {{default initialization of an object of type 'const int' is incompatible with C++}} \
+const int k;        // 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'}}
-const struct S s;   // c-warning {{default initialization of an object of type 'const struct S' is incompatible with C++}} \
+const struct S s;   // zero-init-field-warning {{default initialization of an object of type 'const struct S' is incompatible with C++}} \
                        cxx-error {{call to implicitly-deleted default constructor of 'const struct S'}}
 
 void func() {
-  const int a;        // unsafe-warning {{default initialization of an object of type 'const int' leaves the object uninitialized and is incompatible with C++}} \
+  const int a;        // unsafe-var-warning {{default initialization of an object of type 'const int' leaves the object uninitialized and is incompatible with C++}} \
                          cxx-error {{default initialization of an object of const type 'const int'}}
-  static const int b; // c-warning {{default initialization of an object of type 'const int' is incompatible with C++}} \
+  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'}}
 }
 


        


More information about the cfe-commits mailing list