Author: Timm Bäder
Date: 2024-06-20T16:34:34+02:00
New Revision: 67f5312c41a072aaa725b5943cce2aa0f1643781

URL: 
https://github.com/llvm/llvm-project/commit/67f5312c41a072aaa725b5943cce2aa0f1643781
DIFF: 
https://github.com/llvm/llvm-project/commit/67f5312c41a072aaa725b5943cce2aa0f1643781.diff

LOG: [clang][Interp] Nested ThisExprs that don't refer to the frame this ptr

Use a series of ops in that case, getting us to the right declaration
field.

Added: 
    

Modified: 
    clang/lib/AST/Interp/ByteCodeExprGen.cpp
    clang/lib/AST/Interp/ByteCodeExprGen.h
    clang/lib/AST/Interp/ByteCodeStmtGen.cpp
    clang/lib/AST/Interp/Interp.h
    clang/test/AST/Interp/records.cpp
    clang/test/SemaCXX/uninitialized.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp 
b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
index d26b2ab3f8243..b18873287ffcc 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -34,11 +34,13 @@ template <class Emitter> class DeclScope final : public 
VariableScope<Emitter> {
         OldInitializingDecl(Ctx->InitializingDecl) {
     Ctx->GlobalDecl = Context::shouldBeGloballyIndexed(VD);
     Ctx->InitializingDecl = VD;
+    Ctx->InitStack.push_back(InitLink::Decl(VD));
   }
 
   ~DeclScope() {
     this->Ctx->GlobalDecl = OldGlobalDecl;
     this->Ctx->InitializingDecl = OldInitializingDecl;
+    this->Ctx->InitStack.pop_back();
   }
 
 private:
@@ -72,6 +74,20 @@ template <class Emitter> class OptionScope final {
   bool OldInitializing;
 };
 
+template <class Emitter>
+bool InitLink::emit(ByteCodeExprGen<Emitter> *Ctx, const Expr *E) const {
+  switch (Kind) {
+  case K_This:
+    return Ctx->emitThis(E);
+  case K_Field:
+    // We're assuming there's a base pointer on the stack already.
+    return Ctx->emitGetPtrFieldPop(Offset, E);
+  case K_Decl:
+    return Ctx->visitDeclRef(D, E);
+  }
+  return true;
+}
+
 } // namespace interp
 } // namespace clang
 
@@ -3732,7 +3748,12 @@ template <class Emitter>
 bool ByteCodeExprGen<Emitter>::VisitCXXDefaultInitExpr(
     const CXXDefaultInitExpr *E) {
   SourceLocScope<Emitter> SLS(this, E);
-  return this->delegate(E->getExpr());
+
+  bool Old = InitStackActive;
+  InitStackActive = !isa<FunctionDecl>(E->getUsedContext());
+  bool Result = this->delegate(E->getExpr());
+  InitStackActive = Old;
+  return Result;
 }
 
 template <class Emitter>
@@ -3788,6 +3809,17 @@ bool ByteCodeExprGen<Emitter>::VisitCXXThisExpr(const 
CXXThisExpr *E) {
     return this->emitGetPtrThisField(this->LambdaThisCapture.Offset, E);
   }
 
+  // In some circumstances, the 'this' pointer does not actually refer to the
+  // instance pointer of the current function frame, but e.g. to the 
declaration
+  // currently being initialized. Here we emit the necessary instruction(s) for
+  // this scenario.
+  if (InitStackActive && !InitStack.empty()) {
+    for (const InitLink &IL : InitStack) {
+      if (!IL.emit<Emitter>(this, E))
+        return false;
+    }
+    return true;
+  }
   return this->emitThis(E);
 }
 

diff  --git a/clang/lib/AST/Interp/ByteCodeExprGen.h 
b/clang/lib/AST/Interp/ByteCodeExprGen.h
index 1a62d236b74b9..eef8cae6e38cd 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.h
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -32,10 +32,44 @@ template <class Emitter> class LocalScope;
 template <class Emitter> class DestructorScope;
 template <class Emitter> class VariableScope;
 template <class Emitter> class DeclScope;
+template <class Emitter> class InitLinkScope;
 template <class Emitter> class OptionScope;
 template <class Emitter> class ArrayIndexScope;
 template <class Emitter> class SourceLocScope;
 
+template <class Emitter> class ByteCodeExprGen;
+struct InitLink {
+public:
+  enum {
+    K_This = 0,
+    K_Field = 1,
+    K_Decl = 2,
+  };
+
+  static InitLink This() { return InitLink{K_This}; }
+  static InitLink Field(unsigned Offset) {
+    InitLink IL{K_Field};
+    IL.Offset = Offset;
+    return IL;
+  }
+  static InitLink Decl(const ValueDecl *D) {
+    InitLink IL{K_Decl};
+    IL.D = D;
+    return IL;
+  }
+
+  InitLink(uint8_t Kind) : Kind(Kind) {}
+  template <class Emitter>
+  bool emit(ByteCodeExprGen<Emitter> *Ctx, const Expr *E) const;
+
+private:
+  uint32_t Kind;
+  union {
+    unsigned Offset;
+    const ValueDecl *D;
+  };
+};
+
 /// Compilation context for expressions.
 template <class Emitter>
 class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, 
bool>,
@@ -254,9 +288,11 @@ class ByteCodeExprGen : public 
ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
   friend class LocalScope<Emitter>;
   friend class DestructorScope<Emitter>;
   friend class DeclScope<Emitter>;
+  friend class InitLinkScope<Emitter>;
   friend class OptionScope<Emitter>;
   friend class ArrayIndexScope<Emitter>;
   friend class SourceLocScope<Emitter>;
+  friend struct InitLink;
 
   /// Emits a zero initializer.
   bool visitZeroInitializer(PrimType T, QualType QT, const Expr *E);
@@ -325,6 +361,9 @@ class ByteCodeExprGen : public 
ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
   bool Initializing = false;
   const ValueDecl *InitializingDecl = nullptr;
 
+  llvm::SmallVector<InitLink> InitStack;
+  bool InitStackActive = false;
+
   /// Flag indicating if we're initializing a global variable.
   bool GlobalDecl = false;
 };
@@ -548,6 +587,18 @@ template <class Emitter> class SourceLocScope final {
   bool Enabled = false;
 };
 
+template <class Emitter> class InitLinkScope final {
+public:
+  InitLinkScope(ByteCodeExprGen<Emitter> *Ctx, InitLink &&Link) : Ctx(Ctx) {
+    Ctx->InitStack.push_back(std::move(Link));
+  }
+
+  ~InitLinkScope() { this->Ctx->InitStack.pop_back(); }
+
+private:
+  ByteCodeExprGen<Emitter> *Ctx;
+};
+
 } // namespace interp
 } // namespace clang
 

diff  --git a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp 
b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
index 6ee7898f228de..0618ec1aa8f58 100644
--- a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
@@ -155,8 +155,10 @@ bool ByteCodeStmtGen<Emitter>::visitFunc(const 
FunctionDecl *F) {
         return this->emitInitThisBitField(*T, F, FieldOffset, InitExpr);
       return this->emitInitThisField(*T, FieldOffset, InitExpr);
     }
+
     // Non-primitive case. Get a pointer to the field-to-initialize
     // on the stack and call visitInitialzer() for it.
+    InitLinkScope<Emitter> FieldScope(this, InitLink::Field(F->Offset));
     if (!this->emitGetPtrThisField(FieldOffset, InitExpr))
       return false;
 
@@ -178,6 +180,7 @@ bool ByteCodeStmtGen<Emitter>::visitFunc(const FunctionDecl 
*F) {
     if (!R)
       return false;
 
+    InitLinkScope<Emitter> InitScope(this, InitLink::This());
     for (const auto *Init : Ctor->inits()) {
       // Scope needed for the initializers.
       BlockScope<Emitter> Scope(this);

diff  --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h
index fea83de829261..916d268aa4f09 100644
--- a/clang/lib/AST/Interp/Interp.h
+++ b/clang/lib/AST/Interp/Interp.h
@@ -1432,7 +1432,6 @@ inline bool GetPtrField(InterpState &S, CodePtr OpPC, 
uint32_t Off) {
 
   if (Ptr.isBlockPointer() && Off > Ptr.block()->getSize())
     return false;
-
   S.Stk.push<Pointer>(Ptr.atField(Off));
   return true;
 }

diff  --git a/clang/test/AST/Interp/records.cpp 
b/clang/test/AST/Interp/records.cpp
index 8a18f7a2a4890..9f341f5bc6d1d 100644
--- a/clang/test/AST/Interp/records.cpp
+++ b/clang/test/AST/Interp/records.cpp
@@ -468,19 +468,12 @@ namespace ConditionalInit {
   static_assert(getS(true).a == 12, "");
   static_assert(getS(false).a == 13, "");
 };
-/// FIXME: The following tests are broken.
-///   They are using CXXDefaultInitExprs which contain a CXXThisExpr. The This 
pointer
-///   in those refers to the declaration we are currently initializing, *not* 
the
-///   This pointer of the current stack frame. This is something we haven't
-///   implemented in the new interpreter yet.
 namespace DeclRefs {
-  struct A{ int m; const int &f = m; }; // expected-note {{implicit use of 
'this'}}
+  struct A{ int m; const int &f = m; };
 
-  constexpr A a{10}; // expected-error {{must be initialized by a constant 
expression}} \
-                     // expected-note {{declared here}}
+  constexpr A a{10};
   static_assert(a.m == 10, "");
-  static_assert(a.f == 10, ""); // expected-error {{not an integral constant 
expression}} \
-                                // expected-note {{initializer of 'a' is not a 
constant expression}}
+  static_assert(a.f == 10, "");
 
   class Foo {
   public:
@@ -499,12 +492,8 @@ namespace DeclRefs {
     A a = A{100};
   };
   constexpr B b;
-  /// FIXME: The following two lines don't work because we don't get the
-  ///   pointers on the LHS correct. They make us run into an assertion
-  ///   in CheckEvaluationResult. However, this may just be caused by the
-  ///   problems in the previous examples.
-  //static_assert(b.a.m == 100, "");
-  //static_assert(b.a.f == 100, "");
+  static_assert(b.a.m == 100, "");
+  static_assert(b.a.f == 100, "");
 }
 
 namespace PointerArith {

diff  --git a/clang/test/SemaCXX/uninitialized.cpp 
b/clang/test/SemaCXX/uninitialized.cpp
index c83c2e795824a..8a640c9691b32 100644
--- a/clang/test/SemaCXX/uninitialized.cpp
+++ b/clang/test/SemaCXX/uninitialized.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -fsyntax-only -Wall -Wuninitialized -Wno-unused-value 
-Wno-unused-lambda-capture -Wno-uninitialized-const-reference -std=c++1z 
-verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wall -Wuninitialized -Wno-unused-value 
-Wno-unused-lambda-capture -Wno-uninitialized-const-reference -std=c++1z 
-verify %s -fexperimental-new-constant-interpreter
 
 // definitions for std::move
 namespace std {


        
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to