Index: clang/lib/AST/Interp/Function.h =================================================================== --- clang/lib/AST/Interp/Function.h +++ clang/lib/AST/Interp/Function.h @@ -129,6 +129,8 @@ /// Checks if the function is a constructor. bool isConstructor() const { return isa(F); } + /// Checks if the function is a destructor. + bool isDestructor() const { return isa(F); } /// Checks if the function is fully done compiling. bool isFullyCompiled() const { return IsFullyCompiled; } Index: clang/lib/AST/Interp/Interp.cpp =================================================================== --- clang/lib/AST/Interp/Interp.cpp +++ clang/lib/AST/Interp/Interp.cpp @@ -213,8 +213,15 @@ bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { assert(Ptr.isLive() && "Pointer is not live"); - if (!Ptr.isConst()) { + if (!Ptr.isConst()) return true; + + // The This pointer is writable in constructors and destructors, + // even if isConst() returns true. + if (const Function *Func = S.Current->getFunction(); + Func && (Func->isConstructor() || Func->isDestructor())) { + if (Ptr.block() == S.Current->getThis().block()) + return true; } const QualType Ty = Ptr.getType(); Index: clang/lib/AST/Interp/Pointer.h =================================================================== --- clang/lib/AST/Interp/Pointer.h +++ clang/lib/AST/Interp/Pointer.h @@ -290,6 +290,8 @@ /// Returns the number of elements. unsigned getNumElems() const { return getSize() / elemSize(); } + Block *block() const { return Pointee; } + /// Returns the index into an array. int64_t getIndex() const { if (isElementPastEnd()) Index: clang/test/AST/Interp/cxx20.cpp =================================================================== --- clang/test/AST/Interp/cxx20.cpp +++ clang/test/AST/Interp/cxx20.cpp @@ -201,3 +201,37 @@ // ref-note {{subobject of type 'bool' is not initialized}} #endif }; + +namespace ConstThis { + class Foo { + const int T = 12; // expected-note {{declared const here}} \ + // ref-note {{declared const here}} + int a; + public: + constexpr Foo() { + this->a = 10; + T = 13; // expected-error {{cannot assign to non-static data member 'T' with const-qualified type}} \ + // ref-error {{cannot assign to non-static data member 'T' with const-qualified type}} + } + }; + constexpr Foo F; // expected-error {{must be initialized by a constant expression}} \ + // ref-error {{must be initialized by a constant expression}} + + + class FooDtor { + int a; + public: + constexpr FooDtor() { + this->a = 10; + } + constexpr ~FooDtor() { + this->a = 12; + } + }; + + constexpr int foo() { + const FooDtor f; + return 0; + } + static_assert(foo() == 0); +};