-
Notifications
You must be signed in to change notification settings - Fork 13.4k
[C] Modify -Wdefault-const-init #137961
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
[C] Modify -Wdefault-const-init #137961
Conversation
Post-commit review feedback on llvm#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
@llvm/pr-subscribers-clang Author: Aaron Ballman (AaronBallman) ChangesPost-commit review feedback on #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:
Full diff: https://github.com/llvm/llvm-project/pull/137961.diff 7 Files Affected:
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'}}
}
|
Co-authored-by: Mariya Podchishchaeva <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, this should allow us to try and keep -Wdefault-const-init-var-unsafe
enabled while disabling -Wdefault-const-init-field-unsafe
.
Thanks! |
Post-commit review feedback on llvm#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 <[email protected]>
Post-commit review feedback on llvm#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 <[email protected]>
Post-commit review feedback on llvm#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 <[email protected]>
Post-commit review feedback on llvm#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 <[email protected]>
Post-commit review feedback on #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: