https://github.com/dmpolukhin updated https://github.com/llvm/llvm-project/pull/143168
>From cc00e6ad5192bbd6059542196fac286e7182d153 Mon Sep 17 00:00:00 2001 From: Dmitry Polukhin <dmitry.poluk...@gmail.com> Date: Fri, 23 May 2025 14:22:21 -0700 Subject: [PATCH 1/2] [C++20][Modules] Fix false compilation error with constexpr Use cannonical field decl when evaluating constexpr to avoid resetting computed union value due to using different instances of merged decls. --- clang/lib/AST/ExprConstant.cpp | 2 +- .../constexpr-initialization-failure.cpp | 44 +++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 clang/test/Modules/constexpr-initialization-failure.cpp diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index fa4e10e84de05..6843a37337861 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -6836,7 +6836,7 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This, // and make sure we've initialized every step along it. auto IndirectFieldChain = IFD->chain(); for (auto *C : IndirectFieldChain) { - FD = cast<FieldDecl>(C); + FD = cast<FieldDecl>(C)->getCanonicalDecl(); CXXRecordDecl *CD = cast<CXXRecordDecl>(FD->getParent()); // Switch the union field if it differs. This happens if we had // preceding zero-initialization, and we're now initializing a union diff --git a/clang/test/Modules/constexpr-initialization-failure.cpp b/clang/test/Modules/constexpr-initialization-failure.cpp new file mode 100644 index 0000000000000..8ff20f2fc8ac6 --- /dev/null +++ b/clang/test/Modules/constexpr-initialization-failure.cpp @@ -0,0 +1,44 @@ +// RUN: rm -fR %t +// RUN: split-file %s %t +// RUN: cd %t +// RUN: %clang_cc1 -verify -w -std=c++20 -fmodule-name=h1.h -emit-header-unit -xc++-user-header h1.h -o h1.pcm +// RUN: %clang_cc1 -verify -w -std=c++20 -fmodule-map-file=module.modulemap -fmodule-file=h1.h=h1.pcm main.cpp -o main.o + +//--- module.modulemap +module "h1.h" { + header "h1.h" + export * +} + +//--- h0.h +// expected-no-diagnostics +#pragma once + +template <typename T> struct A { + union { + struct { + T x, y, z; + }; + }; + constexpr A(T, T, T) : x(), y(), z() {} +}; +typedef A<float> packed_vec3; + +//--- h1.h +// expected-no-diagnostics +#pragma once + +#include "h0.h" + +constexpr packed_vec3 kMessThingsUp = packed_vec3(5.0f, 5.0f, 5.0f); + +//--- main.cpp +// expected-no-diagnostics +#include "h0.h" + +static_assert(sizeof(packed_vec3) == sizeof(float) * 3); +static_assert(alignof(packed_vec3) == sizeof(float)); + +import "h1.h"; + +constexpr packed_vec3 kDefaultHalfExtents = packed_vec3(5.0f, 5.0f, 5.0f); >From 15aaef040f615a0f2f5d90d61ee41b13a775012a Mon Sep 17 00:00:00 2001 From: Dmitry Polukhin <dmitry.poluk...@gmail.com> Date: Mon, 9 Jun 2025 02:53:14 -0700 Subject: [PATCH 2/2] Use declaresSameEntity, added release notes. --- clang/docs/ReleaseNotes.rst | 1 + clang/lib/AST/ExprConstant.cpp | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 322686fce0b04..d62ecb438ae68 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -689,6 +689,7 @@ Bug Fixes in This Version - Fixed type mismatch error when 'builtin-elementwise-math' arguments have different qualifiers, this should be well-formed. (#GH141397) - Constant evaluation now correctly runs the destructor of a variable declared in the second clause of a C-style ``for`` loop. (#GH139818) +- Fixed a bug with constexpr evaluation for structs containing unions in case of C++ modules. (#GH143168) Bug Fixes to Compiler Builtins ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 6843a37337861..27ea55e981446 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -6836,7 +6836,7 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This, // and make sure we've initialized every step along it. auto IndirectFieldChain = IFD->chain(); for (auto *C : IndirectFieldChain) { - FD = cast<FieldDecl>(C)->getCanonicalDecl(); + FD = cast<FieldDecl>(C); CXXRecordDecl *CD = cast<CXXRecordDecl>(FD->getParent()); // Switch the union field if it differs. This happens if we had // preceding zero-initialization, and we're now initializing a union @@ -6844,7 +6844,8 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This, // FIXME: In this case, the values of the other subobjects are // specified, since zero-initialization sets all padding bits to zero. if (!Value->hasValue() || - (Value->isUnion() && Value->getUnionField() != FD)) { + (Value->isUnion() && + !declaresSameEntity(Value->getUnionField(), FD))) { if (CD->isUnion()) *Value = APValue(FD); else _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits