diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h index d8f90e45b0ced..8a36db1cd84b4 100644 --- a/clang/lib/AST/ByteCode/Interp.h +++ b/clang/lib/AST/ByteCode/Interp.h @@ -2431,9 +2431,12 @@ inline bool This(InterpState &S, CodePtr OpPC) { // Ensure the This pointer has been cast to the correct base. if (!This.isDummy()) { assert(isa(S.Current->getFunction()->getDecl())); - assert(This.getRecord()); + [[maybe_unused]] const Record *R = This.getRecord(); + if (!R) + R = This.narrow().getRecord(); + assert(R); assert( - This.getRecord()->getDecl() == + R->getDecl() == cast(S.Current->getFunction()->getDecl())->getParent()); } diff --git a/clang/test/AST/ByteCode/placement-new.cpp b/clang/test/AST/ByteCode/placement-new.cpp index 7a4fc89a27dac..c353162a7aab0 100644 --- a/clang/test/AST/ByteCode/placement-new.cpp +++ b/clang/test/AST/ByteCode/placement-new.cpp @@ -339,6 +339,30 @@ namespace PR48606 { static_assert(f()); } +/// This used to crash because of an assertion in the implementation +/// of the This instruction. +namespace ExplicitThisOnArrayElement { + struct S { + int a = 12; + constexpr S(int a) { + this->a = a; + } + }; + + template + constexpr void construct_at(_Tp *__location, _Args &&...__args) { + new (__location) _Tp(__args...); + } + + constexpr bool foo() { + auto *M = std::allocator().allocate(13); // both-note {{allocation performed here was not deallocated}} + construct_at(M, 12); + return true; + } + + static_assert(foo()); // both-error {{not an integral constant expression}} +} + #ifdef BYTECODE constexpr int N = [] // expected-error {{must be initialized by a constant expression}} \ // expected-note {{assignment to dereferenced one-past-the-end pointer is not allowed in a constant expression}} \