Skip to content

Commit 36dd61f

Browse files
authored
[clang][bytecode] Fix activating nested unions (#147338)
When activating the new pointer, we need to de-activate pointers of all parent unions, not just the topmost one.
1 parent 49683ee commit 36dd61f

File tree

2 files changed

+57
-30
lines changed

2 files changed

+57
-30
lines changed

clang/lib/AST/ByteCode/Pointer.cpp

Lines changed: 12 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -520,39 +520,21 @@ void Pointer::activate() const {
520520
}
521521
};
522522

523-
// Unions might be nested etc., so find the topmost Pointer that's
524-
// not in a union anymore.
525-
Pointer UnionPtr = getBase();
526-
while (!UnionPtr.isRoot() && UnionPtr.inUnion())
527-
UnionPtr = UnionPtr.getBase();
528-
529-
assert(UnionPtr.getFieldDesc()->isUnion());
530-
const Record *UnionRecord = UnionPtr.getRecord();
531-
532-
// The direct child pointer of the union that's on the path from
533-
// this pointer to the union.
534-
Pointer ChildPtr = *this;
535-
assert(ChildPtr != UnionPtr);
536-
while (true) {
537-
if (ChildPtr.getBase() == UnionPtr)
538-
break;
539-
ChildPtr = ChildPtr.getBase();
540-
}
541-
assert(ChildPtr.getBase() == UnionPtr);
542-
543-
for (const Record::Field &F : UnionRecord->fields()) {
544-
Pointer FieldPtr = UnionPtr.atField(F.Offset);
545-
if (FieldPtr == ChildPtr) {
546-
// No need to deactivate, will be activated in the next loop.
547-
} else {
548-
deactivate(FieldPtr);
549-
}
550-
}
551-
552523
Pointer B = *this;
553-
while (B != UnionPtr) {
524+
while (!B.isRoot() && B.inUnion()) {
554525
activate(B);
526+
527+
// When walking up the pointer chain, deactivate
528+
// all union child pointers that aren't on our path.
529+
Pointer Cur = B;
555530
B = B.getBase();
531+
if (const Record *BR = B.getRecord(); BR && BR->isUnion()) {
532+
for (const Record::Field &F : BR->fields()) {
533+
Pointer FieldPtr = B.atField(F.Offset);
534+
if (FieldPtr != Cur)
535+
deactivate(FieldPtr);
536+
}
537+
}
556538
}
557539
}
558540

clang/test/AST/ByteCode/cxx23.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,16 @@
44
// RUN: %clang_cc1 -std=c++20 -fsyntax-only -fcxx-exceptions -verify=expected20,all,all20 %s -fexperimental-new-constant-interpreter
55
// RUN: %clang_cc1 -std=c++23 -fsyntax-only -fcxx-exceptions -verify=expected23,all,all23 %s -fexperimental-new-constant-interpreter
66

7+
8+
#define assert_active(F) if (!__builtin_is_within_lifetime(&F)) (1/0);
9+
#define assert_inactive(F) if ( __builtin_is_within_lifetime(&F)) (1/0);
10+
11+
inline constexpr void* operator new(__SIZE_TYPE__, void* p) noexcept { return p; }
12+
namespace std {
13+
template<typename T, typename... Args>
14+
constexpr T* construct_at(T* p, Args&&... args) { return ::new((void*)p) T(static_cast<Args&&>(args)...); }
15+
}
16+
717
constexpr int f(int n) { // all20-error {{constexpr function never produces a constant expression}}
818
static const int m = n; // all-note {{control flows through the definition of a static variable}} \
919
// all20-note {{control flows through the definition of a static variable}} \
@@ -328,3 +338,38 @@ namespace VoidCast {
328338
constexpr int *f = (int*)(void*)b; // all-error {{must be initialized by a constant expression}} \
329339
// all-note {{cast from 'void *' is not allowed in a constant expression}}
330340
}
341+
342+
#if __cplusplus >= 202302L
343+
namespace NestedUnions {
344+
consteval bool test_nested() {
345+
union {
346+
union { int i; char c; } u;
347+
long l;
348+
};
349+
std::construct_at(&l);
350+
assert_active(l);
351+
assert_inactive(u);
352+
353+
std::construct_at(&u);
354+
assert_active(u);
355+
assert_inactive(l);
356+
assert_active(u.i);
357+
assert_inactive(u.c);
358+
359+
std::construct_at(&u.i);
360+
assert_active(u);
361+
assert_inactive(u.c);
362+
363+
364+
std::construct_at(&u.c);
365+
assert_active(u);
366+
assert_inactive(u.i);
367+
assert_active(u.c);
368+
assert_inactive(l);
369+
return true;
370+
}
371+
static_assert(test_nested());
372+
373+
374+
}
375+
#endif

0 commit comments

Comments
 (0)