Author: Timm Bäder Date: 2023-08-20T11:38:29+02:00 New Revision: 39236e9c60e50278d042304b13823e116b68ce78
URL: https://github.com/llvm/llvm-project/commit/39236e9c60e50278d042304b13823e116b68ce78 DIFF: https://github.com/llvm/llvm-project/commit/39236e9c60e50278d042304b13823e116b68ce78.diff LOG: [clang][Interp] Fix lifetime diagnostics for dead records This used to crash the interpreter, either because we ran into the assertion in CheckMutable() or because we accessed a Descriptor* pointer preceding the field of a record. Those are preceded by an InlineDescriptor though. Differential Revision: https://reviews.llvm.org/D152132 Added: clang/test/AST/Interp/lifetimes.cpp Modified: clang/lib/AST/Interp/Descriptor.cpp clang/lib/AST/Interp/InterpBlock.h clang/lib/AST/Interp/InterpState.cpp Removed: ################################################################################ diff --git a/clang/lib/AST/Interp/Descriptor.cpp b/clang/lib/AST/Interp/Descriptor.cpp index 521ad16e367195..b4c26ac88b5c6b 100644 --- a/clang/lib/AST/Interp/Descriptor.cpp +++ b/clang/lib/AST/Interp/Descriptor.cpp @@ -170,9 +170,8 @@ static void moveRecord(Block *B, const std::byte *Src, std::byte *Dst, const Descriptor *D) { for (const auto &F : D->ElemRecord->fields()) { auto FieldOff = F.Offset; - auto FieldDesc = F.Desc; + auto *FieldDesc = F.Desc; - *(reinterpret_cast<Descriptor **>(Dst + FieldOff) - 1) = FieldDesc; if (auto Fn = FieldDesc->MoveFn) Fn(B, Src + FieldOff, Dst + FieldOff, FieldDesc); } diff --git a/clang/lib/AST/Interp/InterpBlock.h b/clang/lib/AST/Interp/InterpBlock.h index 7c6e3f4706f37c..5112108e6f010a 100644 --- a/clang/lib/AST/Interp/InterpBlock.h +++ b/clang/lib/AST/Interp/InterpBlock.h @@ -156,6 +156,7 @@ class DeadBlock final { /// Returns a pointer to the stored data. std::byte *data() { return B.data(); } + std::byte *rawData() { return B.rawData(); } private: friend class Block; diff --git a/clang/lib/AST/Interp/InterpState.cpp b/clang/lib/AST/Interp/InterpState.cpp index 2596c56b4e095c..4f050baea39e79 100644 --- a/clang/lib/AST/Interp/InterpState.cpp +++ b/clang/lib/AST/Interp/InterpState.cpp @@ -58,9 +58,13 @@ void InterpState::deallocate(Block *B) { reinterpret_cast<char *>(std::malloc(sizeof(DeadBlock) + Size)); auto *D = new (Memory) DeadBlock(DeadBlocks, B); - // Move data from one block to another. - if (Desc->MoveFn) + // Move data and metadata from the old block to the new (dead)block. + if (Desc->MoveFn) { Desc->MoveFn(B, B->data(), D->data(), Desc); + if (Desc->getMetadataSize() > 0) + std::memcpy(D->rawData(), B->rawData(), Desc->getMetadataSize()); + } + } else { // Free storage, if necessary. if (Desc->DtorFn) diff --git a/clang/test/AST/Interp/lifetimes.cpp b/clang/test/AST/Interp/lifetimes.cpp new file mode 100644 index 00000000000000..c1046e56892075 --- /dev/null +++ b/clang/test/AST/Interp/lifetimes.cpp @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify %s +// RUN: %clang_cc1 -verify=ref %s + +struct Foo { + int a; +}; + +constexpr int dead1() { // expected-error {{never produces a constant expression}} + + Foo *F2 = nullptr; + { + Foo F{12}; // expected-note 2{{declared here}} + F2 = &F; + } // Ends lifetime of F. + + return F2->a; // expected-note 2{{read of variable whose lifetime has ended}} \ + // ref-note {{read of object outside its lifetime is not allowed in a constant expression}} +} +static_assert(dead1() == 1, ""); // expected-error {{not an integral constant expression}} \ + // expected-note {{in call to}} \ + // ref-error {{not an integral constant expression}} \ + // ref-note {{in call to}} \ + + _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits