Skip to content

Conversation

@AaronBallman
Copy link
Collaborator

A default-initialized union with a const member is generally reasonable in C and isn't necessarily incompatible with C++, so we now silence the diagnostic in that case. However, we do still diagnose a const- qualified, default-initialized union as that is incompatible with C++.

A default-initialized union with a const member is generally reasonable
in C and isn't necessarily incompatible with C++, so we now silence the
diagnostic in that case. However, we do still diagnose a const-
qualified, default-initialized union as that is incompatible with C++.
@AaronBallman AaronBallman requested review from erichkeane and shafik May 20, 2025 13:01
@AaronBallman AaronBallman added clang Clang issues not falling into any other category c clang:frontend Language frontend issues, e.g. anything involving "Sema" labels May 20, 2025
@llvmbot
Copy link
Member

llvmbot commented May 20, 2025

@llvm/pr-subscribers-clang

Author: Aaron Ballman (AaronBallman)

Changes

A default-initialized union with a const member is generally reasonable in C and isn't necessarily incompatible with C++, so we now silence the diagnostic in that case. However, we do still diagnose a const- qualified, default-initialized union as that is incompatible with C++.


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

2 Files Affected:

  • (modified) clang/lib/Sema/SemaInit.cpp (+4-2)
  • (modified) clang/test/Sema/warn-default-const-init.c (+12)
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 9ee8603ff7811..810cac889b98f 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -6602,8 +6602,10 @@ void InitializationSequence::InitializeFrom(Sema &S,
       }
       // If the record has any members which are const (recursively checked),
       // then we want to diagnose those as being uninitialized if there is no
-      // initializer present.
-      if (!Initializer) {
+      // initializer present. However, we only do this for structure types, not
+      // union types, because an unitialized field in a union is generally
+      // reasonable, especially in C where unions can be used for type punning.
+      if (!Initializer && !Rec->isUnion()) {
         if (const FieldDecl *FD = getConstField(Rec)) {
           unsigned DiagID = diag::warn_default_init_const_field_unsafe;
           if (Var->getStorageDuration() == SD_Static ||
diff --git a/clang/test/Sema/warn-default-const-init.c b/clang/test/Sema/warn-default-const-init.c
index e788d72899685..76b85abb6ade2 100644
--- a/clang/test/Sema/warn-default-const-init.c
+++ b/clang/test/Sema/warn-default-const-init.c
@@ -35,6 +35,8 @@ struct V { int i; const struct A a; }; // unsafe-field-note {{member 'a' declare
 struct W { struct A a; const int j; }; // unsafe-field-note {{member 'j' declared 'const' here}} \
                                           unsafe-field-compat-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}}
+union Z1 { int i; const int j; };
+union Z2 { int i; const struct A a; };
 
 void f() {
   struct S s1; // unsafe-field-warning {{default initialization of an object of type 'struct S' with const member leaves the object uninitialized}} \
@@ -66,6 +68,14 @@ void y() {
   struct W w2 = { 0 };
   struct W w3 = { { 0 }, 0 };
 }
+void z() {
+  // Note, we explicitly do not diagnose default initialization of unions with
+  // a const member. Those can be reasonable, the only problematic case is if
+  // the only member of the union is const, but that's a very odd situation to
+  // begin with so we accept it as a false negative.
+  union Z1 z1;
+  union Z2 z2;
+}
 
 // Test a tentative definition which does eventually get an initializer.
 extern const int i;
@@ -77,6 +87,8 @@ const int k;        // zero-init-var-warning {{default initialization of an obje
                        cxx-error {{default initialization of an object of const type 'const int'}}
 const struct S s;   // zero-init-var-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'}}
+const union Z1 z3;  // zero-init-var-warning {{default initialization of an object of type 'const union Z1' is incompatible with C++}} \
+                       cxx-error {{default initialization of an object of const type 'const union Z1' without a user-provided default constructor}}
 
 void func() {
   const int a;        // unsafe-var-warning {{default initialization of an object of type 'const int' leaves the object uninitialized}} \

Copy link
Collaborator

@shafik shafik left a comment

Choose a reason for hiding this comment

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

LGTM

@AaronBallman AaronBallman merged commit 6fb23af into llvm:main May 20, 2025
15 checks passed
@AaronBallman AaronBallman deleted the aballman-default-const-init-union branch May 20, 2025 17:04
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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants