[clang] [Clang][Sema] Diagnosis for constexpr constructor not initializing a union member (PR #81225)

via cfe-commits cfe-commits at lists.llvm.org
Thu Feb 8 20:32:53 PST 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: None (mahtohappy)

<details>
<summary>Changes</summary>

For templates, isDependentContext() is true, that's why the previous if check was failing.
Here, we traverse the RD and upon finding a Union declaration we check if at least one member of the union is initialized.
If not, it produces a diagnosis for it.
Fix #<!-- -->46689 

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


4 Files Affected:

- (modified) clang/docs/ReleaseNotes.rst (+3-2) 
- (modified) clang/lib/Sema/SemaDeclCXX.cpp (+37-11) 
- (modified) clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp (+4-2) 
- (added) clang/test/SemaCXX/constexpr-union-temp-ctor-cxx.cpp (+27) 


``````````diff
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 32440ee64e3ebe..0072495354b8eb 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -149,9 +149,10 @@ Improvements to Clang's diagnostics
   prints.
 
 - Clang now diagnoses member template declarations with multiple declarators.
+- Clang now diagnoses use of the ``template`` keyword after declarative nested name specifiers.
 
-- Clang now diagnoses use of the ``template`` keyword after declarative nested
-  name specifiers.
+- Clang now diagnoses constexpr constructor for not initializing atleast one member of union
+- Fixes(`#46689 Constexpr constructor not initializing a union member is not diagnosed`)
 
 - The ``-Wshorten-64-to-32`` diagnostic is now grouped under ``-Wimplicit-int-conversion`` instead
    of ``-Wconversion``. Fixes `#69444 <https://github.com/llvm/llvm-project/issues/69444>`_.
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index fea8c5036c80b1..f6c7410e3be92a 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -1795,6 +1795,12 @@ static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl,
                                        Stmt *Body,
                                        Sema::CheckConstexprKind Kind);
 
+static bool
+checkUnionConstructorIntializer(Sema &SemaRef, const FunctionDecl *Dcl,
+                                const CXXConstructorDecl *Constructor,
+                                const CXXRecordDecl *RD,
+                                Sema::CheckConstexprKind Kind);
+
 // Check whether a function declaration satisfies the requirements of a
 // constexpr function definition or a constexpr constructor definition. If so,
 // return true. If not, produce appropriate diagnostics (unless asked not to by
@@ -2343,17 +2349,9 @@ static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl,
     // - if the class is a union having variant members, exactly one of them
     //   shall be initialized;
     if (RD->isUnion()) {
-      if (Constructor->getNumCtorInitializers() == 0 &&
-          RD->hasVariantMembers()) {
-        if (Kind == Sema::CheckConstexprKind::Diagnose) {
-          SemaRef.Diag(
-              Dcl->getLocation(),
-              SemaRef.getLangOpts().CPlusPlus20
-                  ? diag::warn_cxx17_compat_constexpr_union_ctor_no_init
-                  : diag::ext_constexpr_union_ctor_no_init);
-        } else if (!SemaRef.getLangOpts().CPlusPlus20) {
-          return false;
-        }
+      if (checkUnionConstructorIntializer(SemaRef, Dcl, Constructor, RD,
+                                          Kind)) {
+        return false;
       }
     } else if (!Constructor->isDependentContext() &&
                !Constructor->isDelegatingConstructor()) {
@@ -2393,6 +2391,17 @@ static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl,
                                              Kind))
             return false;
       }
+    } else if (!Constructor->isDelegatingConstructor()) {
+      for (const Decl *Decls : RD->decls()) {
+        if (const auto *Inner = dyn_cast<CXXRecordDecl>(Decls)) {
+          if (Inner->isUnion()) {
+            if (checkUnionConstructorIntializer(SemaRef, Dcl, Constructor,
+                                                Inner, Kind)) {
+              return true;
+            }
+          }
+        }
+      }
     }
   } else {
     if (ReturnStmts.empty()) {
@@ -2471,6 +2480,23 @@ static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl,
   return true;
 }
 
+static bool
+checkUnionConstructorIntializer(Sema &SemaRef, const FunctionDecl *Dcl,
+                                const CXXConstructorDecl *Constructor,
+                                const CXXRecordDecl *RD,
+                                Sema::CheckConstexprKind Kind) {
+  if (Constructor->getNumCtorInitializers() == 0 && RD->hasVariantMembers()) {
+    if (Kind == Sema::CheckConstexprKind::Diagnose) {
+      SemaRef.Diag(Dcl->getLocation(),
+                   SemaRef.getLangOpts().CPlusPlus20
+                       ? diag::warn_cxx17_compat_constexpr_union_ctor_no_init
+                       : diag::ext_constexpr_union_ctor_no_init);
+    } else if (!SemaRef.getLangOpts().CPlusPlus20) {
+      return true;
+    }
+  }
+  return false;
+}
 bool Sema::CheckImmediateEscalatingFunctionDefinition(
     FunctionDecl *FD, const sema::FunctionScopeInfo *FSI) {
   if (!getLangOpts().CPlusPlus20 || !FD->isImmediateEscalating())
diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp
index f1f677ebfcd341..a4434d1c35943f 100644
--- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp
+++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp
@@ -222,8 +222,10 @@ struct TemplateInit {
     T g;
     T h;
   };
-  // FIXME: This is ill-formed (no diagnostic required). We should diagnose it.
-  constexpr TemplateInit() {} // desired-error {{must initialize all members}}
+  constexpr TemplateInit() {}
+#ifndef CXX2A
+  // expected-error at -2 {{constexpr union constructor that does not initialize any member is a C++20 extension}}
+#endif
 };
 template<typename T> struct TemplateInit2 {
   Literal l;
diff --git a/clang/test/SemaCXX/constexpr-union-temp-ctor-cxx.cpp b/clang/test/SemaCXX/constexpr-union-temp-ctor-cxx.cpp
new file mode 100644
index 00000000000000..51d5e1d8cf9341
--- /dev/null
+++ b/clang/test/SemaCXX/constexpr-union-temp-ctor-cxx.cpp
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -std=c++14 -verify -fcxx-exceptions -Werror=c++14-extensions -Werror=c++20-extensions %s
+
+template <class> struct C {
+    union {
+      int i;
+    };
+    constexpr C() {} // expected-error {{constexpr union constructor that does not initialize any member is a C++20 extension}}
+};
+constexpr C<int> c;
+
+template <class> class D {
+    union {
+      int i;
+    };
+public:
+    constexpr D() {} // expected-error {{constexpr union constructor that does not initialize any member is a C++20 extension}}
+};
+constexpr D<int> d;
+
+template<typename T>
+struct Foo {
+    union {
+      int i;
+    };
+    constexpr Foo(int a): i(a){}
+};
+constexpr Foo<int> f(5);

``````````

</details>


https://github.com/llvm/llvm-project/pull/81225


More information about the cfe-commits mailing list