llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Aaron Ballman (AaronBallman) <details> <summary>Changes</summary> 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 ``` --- Full diff: https://github.com/llvm/llvm-project/pull/137961.diff 7 Files Affected: - (modified) clang/docs/ReleaseNotes.rst (+10-6) - (modified) clang/include/clang/Basic/DiagnosticGroups.td (+10-2) - (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+12-6) - (modified) clang/lib/Sema/Sema.cpp (+1-1) - (modified) clang/lib/Sema/SemaDecl.cpp (+1-1) - (modified) clang/lib/Sema/SemaInit.cpp (+3-3) - (modified) clang/test/Sema/warn-default-const-init.c (+14-19) ``````````diff diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index bc68bb8b70b3d..4fb606afc0f14 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 fc1ce197ef134..3835cd7251488 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -157,8 +157,16 @@ def C99Compat : DiagGroup<"c99-compat">; def C23Compat : DiagGroup<"c23-compat">; def : DiagGroup<"c2x-compat", [C23Compat]>; 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 ad5bf26be2590..90a7cac9df29e 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -8206,14 +8206,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 dfc718eedc1d9..ecc9909682522 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 a85eca4d4ac3c..9bf67ce31446e 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -6590,12 +6590,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..d1e60e5db28c7 100644 --- a/clang/test/Sema/warn-default-const-init.c +++ b/clang/test/Sema/warn-default-const-init.c @@ -1,28 +1,23 @@ -// 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 +26,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 +42,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'}} } `````````` </details> https://github.com/llvm/llvm-project/pull/137961 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits