From d44bc6ce6fdcd6607b987a74c417e48daf304124 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= Date: Sun, 11 Aug 2024 10:25:12 +0200 Subject: [PATCH] [clang][Interp] Propagate InUnion flag to base classes --- clang/lib/AST/Interp/Descriptor.cpp | 11 ++++++----- clang/test/AST/Interp/unions.cpp | 23 +++++++++++++++++++++++ 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/clang/lib/AST/Interp/Descriptor.cpp b/clang/lib/AST/Interp/Descriptor.cpp index 634413b2f2f52a..1b7d9f03f8ef0d 100644 --- a/clang/lib/AST/Interp/Descriptor.cpp +++ b/clang/lib/AST/Interp/Descriptor.cpp @@ -171,30 +171,31 @@ static void initBase(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable, unsigned FieldOffset, bool IsVirtualBase) { assert(D); assert(D->ElemRecord); + assert(!D->ElemRecord->isUnion()); // Unions cannot be base classes. - bool IsUnion = D->ElemRecord->isUnion(); auto *Desc = reinterpret_cast(Ptr + FieldOffset) - 1; Desc->Offset = FieldOffset; Desc->Desc = D; Desc->IsInitialized = D->IsArray; Desc->IsBase = true; Desc->IsVirtualBase = IsVirtualBase; - Desc->IsActive = IsActive && !IsUnion; + Desc->IsActive = IsActive && !InUnion; Desc->IsConst = IsConst || D->IsConst; Desc->IsFieldMutable = IsMutable || D->IsMutable; + Desc->InUnion = InUnion; for (const auto &V : D->ElemRecord->bases()) initBase(B, Ptr + FieldOffset, IsConst, IsMutable, IsActive, InUnion, V.Desc, V.Offset, false); for (const auto &F : D->ElemRecord->fields()) initField(B, Ptr + FieldOffset, IsConst, IsMutable, IsActive, InUnion, - IsUnion, F.Desc, F.Offset); + InUnion, F.Desc, F.Offset); } static void ctorRecord(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable, bool IsActive, bool InUnion, const Descriptor *D) { for (const auto &V : D->ElemRecord->bases()) - initBase(B, Ptr, IsConst, IsMutable, IsActive, false, V.Desc, V.Offset, + initBase(B, Ptr, IsConst, IsMutable, IsActive, InUnion, V.Desc, V.Offset, false); for (const auto &F : D->ElemRecord->fields()) { bool IsUnionField = D->isUnion(); @@ -202,7 +203,7 @@ static void ctorRecord(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable, InUnion || IsUnionField, F.Desc, F.Offset); } for (const auto &V : D->ElemRecord->virtual_bases()) - initBase(B, Ptr, IsConst, IsMutable, IsActive, false, V.Desc, V.Offset, + initBase(B, Ptr, IsConst, IsMutable, IsActive, InUnion, V.Desc, V.Offset, true); } diff --git a/clang/test/AST/Interp/unions.cpp b/clang/test/AST/Interp/unions.cpp index 4c60c2c0810d4c..996d29e143fe2c 100644 --- a/clang/test/AST/Interp/unions.cpp +++ b/clang/test/AST/Interp/unions.cpp @@ -358,4 +358,27 @@ namespace CopyCtor { static_assert(y.b == 42, ""); // both-error {{constant expression}} \ // both-note {{'b' of union with active member 'a'}} } + +namespace UnionInBase { + struct Base { + int y; + }; + struct A : Base { + int x; + int arr[3]; + union { int p, q; }; + }; + union B { + A a; + int b; + }; + constexpr int read_wrong_member_indirect() { // both-error {{never produces a constant}} + B b = {.b = 1}; + int *p = &b.a.y; + return *p; // both-note 2{{read of member 'a' of union with active member 'b'}} + + } + static_assert(read_wrong_member_indirect() == 1); // both-error {{not an integral constant expression}} \ + // both-note {{in call to}} +} #endif