https://github.com/mahtohappy created https://github.com/llvm/llvm-project/pull/81225
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 >From aeb0686c76f2745111acd92c0d6b77faf69d2ed6 Mon Sep 17 00:00:00 2001 From: mahtohappy <happy.ku...@windriver.com> Date: Thu, 8 Feb 2024 10:51:22 -0800 Subject: [PATCH 1/2] [Clang][Sema] Diagnosis for constexpr constructor not initializing a union member --- clang/docs/ReleaseNotes.rst | 5 +- clang/lib/Sema/SemaDeclCXX.cpp | 47 ++++++++++++++----- .../CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp | 3 ++ .../SemaCXX/constexpr-union-temp-ctor-cxx.cpp | 27 +++++++++++ 4 files changed, 69 insertions(+), 13 deletions(-) create mode 100644 clang/test/SemaCXX/constexpr-union-temp-ctor-cxx.cpp 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..8da4f095765661 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -1795,6 +1795,11 @@ 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 +2348,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 +2390,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 +2479,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..37c9e2c36ad657 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 @@ -224,6 +224,9 @@ struct TemplateInit { }; // FIXME: This is ill-formed (no diagnostic required). We should diagnose it. constexpr TemplateInit() {} // desired-error {{must initialize all members}} +#ifndef CXX2A + // expected-error@-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); >From 50914b46d2360915d2a88de99fa6b7eb28197c99 Mon Sep 17 00:00:00 2001 From: mahtohappy <happy.ku...@windriver.com> Date: Thu, 8 Feb 2024 10:51:22 -0800 Subject: [PATCH 2/2] [Clang][Sema] Diagnosis for constexpr constructor not initializing a union member --- clang/lib/Sema/SemaDeclCXX.cpp | 9 +++++---- clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp | 3 +-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 8da4f095765661..f6c7410e3be92a 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -1795,10 +1795,11 @@ 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); +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, 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 37c9e2c36ad657..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,7 @@ 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@-2 {{constexpr union constructor that does not initialize any member is a C++20 extension}} #endif _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits