Author: Timm Bäder Date: 2023-03-01T15:41:10+01:00 New Revision: 8d09bd616be8e347d2769d7b17cd8e717c855c45
URL: https://github.com/llvm/llvm-project/commit/8d09bd616be8e347d2769d7b17cd8e717c855c45 DIFF: https://github.com/llvm/llvm-project/commit/8d09bd616be8e347d2769d7b17cd8e717c855c45.diff LOG: [clang][Interp] This pointers are writable in de-/constructors This is possible in C++20, so we need to check this when doing stores. Differential Revision: https://reviews.llvm.org/D136751 Added: Modified: clang/lib/AST/Interp/Function.h clang/lib/AST/Interp/Interp.cpp clang/lib/AST/Interp/Pointer.h clang/test/AST/Interp/cxx20.cpp Removed: ################################################################################ diff --git a/clang/lib/AST/Interp/Function.h b/clang/lib/AST/Interp/Function.h index 1eb4fa90d794..422211708a77 100644 --- a/clang/lib/AST/Interp/Function.h +++ b/clang/lib/AST/Interp/Function.h @@ -134,6 +134,8 @@ class Function final { /// Checks if the function is a constructor. bool isConstructor() const { return isa<CXXConstructorDecl>(F); } + /// Checks if the function is a destructor. + bool isDestructor() const { return isa<CXXDestructorDecl>(F); } /// Checks if the function is fully done compiling. bool isFullyCompiled() const { return IsFullyCompiled; } diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp index 319aba0ffa94..329cc0ff949d 100644 --- a/clang/lib/AST/Interp/Interp.cpp +++ b/clang/lib/AST/Interp/Interp.cpp @@ -213,7 +213,14 @@ bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 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()) && + Ptr.block() == S.Current->getThis().block()) { return true; } diff --git a/clang/lib/AST/Interp/Pointer.h b/clang/lib/AST/Interp/Pointer.h index 489884a25659..5895c61295e0 100644 --- a/clang/lib/AST/Interp/Pointer.h +++ b/clang/lib/AST/Interp/Pointer.h @@ -290,6 +290,8 @@ class Pointer { /// 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()) diff --git a/clang/test/AST/Interp/cxx20.cpp b/clang/test/AST/Interp/cxx20.cpp index e9505b3cf718..44c97dd1afcd 100644 --- a/clang/test/AST/Interp/cxx20.cpp +++ b/clang/test/AST/Interp/cxx20.cpp @@ -201,3 +201,74 @@ constexpr Derived D; // expected-error {{must be initialized by a constant expre // 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); + + template <bool Good> + struct ctor_test { + int a = 0; + + constexpr ctor_test() { + if (Good) + a = 10; + int local = 100 / a; // expected-note {{division by zero}} \ + // ref-note {{division by zero}} + } + }; + + template <bool Good> + struct dtor_test { + int a = 0; + + constexpr dtor_test() = default; + constexpr ~dtor_test() { + if (Good) + a = 10; + int local = 100 / a; // expected-note {{division by zero}} \ + // ref-note {{division by zero}} + } + }; + + constexpr ctor_test<true> good_ctor; + constexpr dtor_test<true> good_dtor; + + constexpr ctor_test<false> bad_ctor; // expected-error {{must be initialized by a constant expression}} \ + // expected-note {{in call to}} \ + // ref-error {{must be initialized by a constant expression}} \ + // ref-note {{in call to}} + constexpr dtor_test<false> bad_dtor; // expected-error {{must have constant destruction}} \ + // expected-note {{in call to}} \ + // ref-error {{must have constant destruction}} \ + // ref-note {{in call to}} +}; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits