Author: Yanzuo Liu Date: 2026-02-05T16:37:58+01:00 New Revision: ddda8d7d259826e9a686469d531787ea223d727d
URL: https://github.com/llvm/llvm-project/commit/ddda8d7d259826e9a686469d531787ea223d727d DIFF: https://github.com/llvm/llvm-project/commit/ddda8d7d259826e9a686469d531787ea223d727d.diff LOG: [clang][bytecode] Fix reading union template parameter object (#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 --------- Co-authored-by: Timm Baeder <[email protected]> Added: Modified: clang/lib/AST/ByteCode/Compiler.cpp clang/test/AST/ByteCode/cxx20.cpp Removed: ################################################################################ diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index eb52112f16b82..a0138c402e143 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -5069,14 +5069,29 @@ bool Compiler<Emitter>::visitAPValueInitializer(const APValue &Val, } if (Val.isUnion()) { const FieldDecl *UnionField = Val.getUnionField(); - const Record *R = this->getRecord(UnionField->getParent()); + if (!UnionField) + 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 +7141,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
