diff --git a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp --- a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp @@ -98,7 +98,8 @@ if (const auto Ctor = dyn_cast(F)) { const RecordDecl *RD = Ctor->getParent(); const Record *R = this->getRecord(RD); - assert(R); + if (!R) + return false; for (const auto *Init : Ctor->inits()) { const Expr *InitExpr = Init->getInit(); diff --git a/clang/lib/AST/Interp/Program.h b/clang/lib/AST/Interp/Program.h --- a/clang/lib/AST/Interp/Program.h +++ b/clang/lib/AST/Interp/Program.h @@ -51,8 +51,10 @@ // Records might actually allocate memory themselves, but they // are allocated using a BumpPtrAllocator. Call their desctructors // here manually so they are properly freeing their resources. - for (auto RecordPair : Records) - RecordPair.second->~Record(); + for (auto RecordPair : Records) { + if (Record *R = RecordPair.second) + R->~Record(); + } } /// Marshals a native pointer to an ID for embedding in bytecode. diff --git a/clang/lib/AST/Interp/Program.cpp b/clang/lib/AST/Interp/Program.cpp --- a/clang/lib/AST/Interp/Program.cpp +++ b/clang/lib/AST/Interp/Program.cpp @@ -221,6 +221,11 @@ return It->second; } + // We insert nullptr now and replace that later, so recursive calls + // to this function with the same RecordDecl don't run into + // infinite recursion. + Records.insert({RD, nullptr}); + // Number of bytes required by fields and base classes. unsigned BaseSize = 0; // Number of bytes required by virtual base. @@ -294,7 +299,7 @@ Record *R = new (Allocator) Record(RD, std::move(Bases), std::move(Fields), std::move(VirtBases), VirtSize, BaseSize); - Records.insert({RD, R}); + Records[RD] = R; return R; } diff --git a/clang/test/AST/Interp/records.cpp b/clang/test/AST/Interp/records.cpp --- a/clang/test/AST/Interp/records.cpp +++ b/clang/test/AST/Interp/records.cpp @@ -133,6 +133,20 @@ constexpr C RVOAndParamsResult = RVOAndParams(&c); #endif +class Bar { // expected-note {{definition of 'Bar' is not complete}} \ + // ref-note {{definition of 'Bar' is not complete}} +public: + constexpr Bar(){} + constexpr Bar b; // expected-error {{cannot be constexpr}} \ + // expected-error {{has incomplete type 'const Bar'}} \ + // ref-error {{cannot be constexpr}} \ + // ref-error {{has incomplete type 'const Bar'}} +}; +constexpr Bar B; // expected-error {{must be initialized by a constant expression}} \ + // expected-error {{failed to evaluate an expression}} \ + // ref-error {{must be initialized by a constant expression}} +constexpr Bar *pb = nullptr; + constexpr int locals() { C c; c.a = 10;