[clang] [clang][bytecode] Fix reading union template parameter object (PR #179899)
Yanzuo Liu via cfe-commits
cfe-commits at lists.llvm.org
Thu Feb 5 06:19:57 PST 2026
https://github.com/zwuis updated https://github.com/llvm/llvm-project/pull/179899
>From 16bc25e35bac87d7b1cedbe7ce9766fdb6498ace Mon Sep 17 00:00:00 2001
From: Yanzuo Liu <zwuis at outlook.com>
Date: Thu, 5 Feb 2026 18:05:57 +0800
Subject: [PATCH 1/2] 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;
>From 1067dd4c2233f32d99e0b965f77d3d155a502342 Mon Sep 17 00:00:00 2001
From: Yanzuo Liu <zwuis at outlook.com>
Date: Thu, 5 Feb 2026 22:19:48 +0800
Subject: [PATCH 2/2] Update clang/lib/AST/ByteCode/Compiler.cpp
Co-authored-by: Timm Baeder <tbaeder at redhat.com>
---
clang/lib/AST/ByteCode/Compiler.cpp | 1 -
1 file changed, 1 deletion(-)
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 673c603f27f4e..a0138c402e143 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -5070,7 +5070,6 @@ bool Compiler<Emitter>::visitAPValueInitializer(const APValue &Val,
if (Val.isUnion()) {
const FieldDecl *UnionField = Val.getUnionField();
if (!UnionField)
- // no active fields
return true;
const Record *R = this->getRecord(T);
assert(R);
More information about the cfe-commits
mailing list