https://github.com/zwuis created https://github.com/llvm/llvm-project/pull/179899
Before this patch, reading union template parameter object will trigger diagnostics saying it's not initialized. This patch fixes this issue. Reading union template parameter with no active fields, class type fields, or bit-fields is handled as a drive-by. AI usage: The implementation was generated by AI and modified by me afterwards. Assisted-by: GPT-5.2 >From 16bc25e35bac87d7b1cedbe7ce9766fdb6498ace Mon Sep 17 00:00:00 2001 From: Yanzuo Liu <[email protected]> Date: Thu, 5 Feb 2026 18:05:57 +0800 Subject: [PATCH] Fix reading union template parameter object --- clang/lib/AST/ByteCode/Compiler.cpp | 29 +++++++++++++++++++++++------ clang/test/AST/ByteCode/cxx20.cpp | 24 ++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 6 deletions(-) diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index eb52112f16b82..673c603f27f4e 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -5069,14 +5069,30 @@ bool Compiler<Emitter>::visitAPValueInitializer(const APValue &Val, } if (Val.isUnion()) { const FieldDecl *UnionField = Val.getUnionField(); - const Record *R = this->getRecord(UnionField->getParent()); + if (!UnionField) + // no active fields + return true; + const Record *R = this->getRecord(T); assert(R); const APValue &F = Val.getUnionValue(); const Record::Field *RF = R->getField(UnionField); - PrimType T = classifyPrim(RF->Decl->getType()); - if (!this->visitAPValue(F, T, E)) + QualType FieldType = RF->Decl->getType(); + + if (OptPrimType PT = classify(FieldType)) { + if (!this->visitAPValue(F, *PT, E)) + return false; + if (RF->isBitField()) + return this->emitInitBitFieldActivate(*PT, RF, E); + return this->emitInitFieldActivate(*PT, RF->Offset, E); + } + + if (!this->emitGetPtrField(RF->Offset, E)) return false; - return this->emitInitField(T, RF->Offset, E); + if (!this->emitActivate(E)) + return false; + if (!this->visitAPValueInitializer(F, E, FieldType)) + return false; + return this->emitPopPtr(E); } if (Val.isArray()) { const auto *ArrType = T->getAsArrayTypeUnsafe(); @@ -7126,8 +7142,9 @@ bool Compiler<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) { return false; return this->emitInitGlobal(*T, *Index, E); } - return this->visitAPValueInitializer(TPOD->getValue(), E, - TPOD->getType()); + if (!this->visitAPValueInitializer(TPOD->getValue(), E, TPOD->getType())) + return false; + return this->emitFinishInit(E); } return false; } diff --git a/clang/test/AST/ByteCode/cxx20.cpp b/clang/test/AST/ByteCode/cxx20.cpp index 2abe8dd120e6f..139b6c873adce 100644 --- a/clang/test/AST/ByteCode/cxx20.cpp +++ b/clang/test/AST/ByteCode/cxx20.cpp @@ -785,6 +785,30 @@ namespace APValues { constexpr const A &w = get<A{1, &g, &A::n, "hello"}>; } +namespace InitFromAPValues { + template <auto a> struct S { + static constexpr auto &ref = a; + }; + + union U1 { int x, y; }; + static_assert(S<U1{1}>::ref.x == 1); + static_assert(S<U1{1}>::ref.y == 1); // both-error {{static assertion expression is not an integral constant expression}} \ + // both-note {{read of member 'y' of union with active member 'x' is not allowed in a constant expression}} + + union U2 { + bool x; + constexpr U2() {} + }; + static_assert(S<U2{}>::ref.x); // both-error {{static assertion expression is not an integral constant expression}} \ + // both-note {{read of member 'x' of union with no active member is not allowed in a constant expression}} + + union U3 { + struct S { int x; }; + S s; + }; + static_assert(S<U3{2}>::ref.s.x == 2); +} + namespace self_referencing { struct S { S* ptr = nullptr; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
