[clang] [WIP][Clang][Interp] Fix display of syntactically-invalid note for member function calls (PR #102170)

via cfe-commits cfe-commits at lists.llvm.org
Tue Aug 6 08:51:48 PDT 2024


https://github.com/yronglin created https://github.com/llvm/llvm-project/pull/102170

None

>From 59706e6788e36dbd30d876a3cc5541f224c62af3 Mon Sep 17 00:00:00 2001
From: yronglin <yronglin777 at gmail.com>
Date: Tue, 6 Aug 2024 23:50:34 +0800
Subject: [PATCH] [WIP][Clang][Interp] Fix display of syntactically-invalid
 note for member function calls

Signed-off-by: yronglin <yronglin777 at gmail.com>
---
 clang/lib/AST/Interp/Compiler.cpp           | 18 +++++-----
 clang/lib/AST/Interp/Context.cpp            |  2 +-
 clang/lib/AST/Interp/EvalEmitter.cpp        |  4 +--
 clang/lib/AST/Interp/Interp.cpp             |  2 +-
 clang/lib/AST/Interp/Interp.h               | 18 +++++-----
 clang/lib/AST/Interp/InterpFrame.cpp        | 37 ++++++++++++++++-----
 clang/lib/AST/Interp/InterpFrame.h          |  6 ++--
 clang/lib/AST/Interp/Opcodes.td             |  6 ++--
 clang/test/AST/Interp/constexpr-nqueens.cpp |  2 +-
 clang/test/AST/Interp/lambda.cpp            |  2 +-
 clang/test/AST/Interp/records.cpp           |  4 +--
 11 files changed, 61 insertions(+), 40 deletions(-)

diff --git a/clang/lib/AST/Interp/Compiler.cpp b/clang/lib/AST/Interp/Compiler.cpp
index 02cbe38f5fb1f..9cfc50299d660 100644
--- a/clang/lib/AST/Interp/Compiler.cpp
+++ b/clang/lib/AST/Interp/Compiler.cpp
@@ -2551,10 +2551,10 @@ bool Compiler<Emitter>::VisitCXXConstructExpr(const CXXConstructExpr *E) {
         VarArgSize +=
             align(primSize(classify(E->getArg(I)->getType()).value_or(PT_Ptr)));
       }
-      if (!this->emitCallVar(Func, VarArgSize, E))
+      if (!this->emitCallVar(Func, VarArgSize, E, E))
         return false;
     } else {
-      if (!this->emitCall(Func, 0, E))
+      if (!this->emitCall(Func, 0, E, E))
         return false;
     }
 
@@ -2588,7 +2588,7 @@ bool Compiler<Emitter>::VisitCXXConstructExpr(const CXXConstructExpr *E) {
           return false;
       }
 
-      if (!this->emitCall(Func, 0, E))
+      if (!this->emitCall(Func, 0, E, E))
         return false;
     }
     return true;
@@ -2799,7 +2799,7 @@ bool Compiler<Emitter>::VisitCXXInheritedCtorInitExpr(
     Offset += align(primSize(PT));
   }
 
-  return this->emitCall(F, 0, E);
+  return this->emitCall(F, 0, E, E);
 }
 
 template <class Emitter>
@@ -4087,7 +4087,7 @@ bool Compiler<Emitter>::VisitCallExpr(const CallExpr *E) {
       for (unsigned I = NumParams, N = E->getNumArgs(); I != N; ++I)
         VarArgSize += align(primSize(classify(E->getArg(I)).value_or(PT_Ptr)));
 
-      if (!this->emitCallVirt(Func, VarArgSize, E))
+      if (!this->emitCallVirt(Func, VarArgSize, E, E))
         return false;
     } else if (Func->isVariadic()) {
       uint32_t VarArgSize = 0;
@@ -4095,10 +4095,10 @@ bool Compiler<Emitter>::VisitCallExpr(const CallExpr *E) {
           Func->getNumWrittenParams() + isa<CXXOperatorCallExpr>(E);
       for (unsigned I = NumParams, N = E->getNumArgs(); I != N; ++I)
         VarArgSize += align(primSize(classify(E->getArg(I)).value_or(PT_Ptr)));
-      if (!this->emitCallVar(Func, VarArgSize, E))
+      if (!this->emitCallVar(Func, VarArgSize, E, E))
         return false;
     } else {
-      if (!this->emitCall(Func, 0, E))
+      if (!this->emitCall(Func, 0, E, E))
         return false;
     }
   } else {
@@ -4705,7 +4705,7 @@ bool Compiler<Emitter>::emitLambdaStaticInvokerBody(const CXXMethodDecl *MD) {
       return false;
   }
 
-  if (!this->emitCall(Func, 0, LambdaCallOp))
+  if (!this->emitCall(Func, 0, nullptr, LambdaCallOp))
     return false;
 
   this->emitCleanup();
@@ -5567,7 +5567,7 @@ bool Compiler<Emitter>::emitRecordDestruction(const Record *R) {
     assert(DtorFunc->getNumParams() == 1);
     if (!this->emitDupPtr(SourceInfo{}))
       return false;
-    if (!this->emitCall(DtorFunc, 0, SourceInfo{}))
+    if (!this->emitCall(DtorFunc, 0, nullptr, SourceInfo{}))
       return false;
   }
 
diff --git a/clang/lib/AST/Interp/Context.cpp b/clang/lib/AST/Interp/Context.cpp
index 92ac28137fdb4..6ea61bdc44553 100644
--- a/clang/lib/AST/Interp/Context.cpp
+++ b/clang/lib/AST/Interp/Context.cpp
@@ -206,7 +206,7 @@ bool Context::Run(State &Parent, const Function *Func, APValue &Result) {
   {
     InterpState State(Parent, *P, Stk, *this);
     State.Current = new InterpFrame(State, Func, /*Caller=*/nullptr, CodePtr(),
-                                    Func->getArgSize());
+                                    Func->getArgSize(), /*CE=*/nullptr);
     if (Interpret(State, Result)) {
       assert(Stk.empty());
       return true;
diff --git a/clang/lib/AST/Interp/EvalEmitter.cpp b/clang/lib/AST/Interp/EvalEmitter.cpp
index 08536536ac3c2..99a7e9212aea1 100644
--- a/clang/lib/AST/Interp/EvalEmitter.cpp
+++ b/clang/lib/AST/Interp/EvalEmitter.cpp
@@ -20,8 +20,8 @@ EvalEmitter::EvalEmitter(Context &Ctx, Program &P, State &Parent,
                          InterpStack &Stk)
     : Ctx(Ctx), P(P), S(Parent, P, Stk, Ctx, this), EvalResult(&Ctx) {
   // Create a dummy frame for the interpreter which does not have locals.
-  S.Current =
-      new InterpFrame(S, /*Func=*/nullptr, /*Caller=*/nullptr, CodePtr(), 0);
+  S.Current = new InterpFrame(S, /*Func=*/nullptr, /*Caller=*/nullptr,
+                              CodePtr(), 0, /*CE=*/nullptr);
 }
 
 EvalEmitter::~EvalEmitter() {
diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp
index 0f72b860ddad7..c80adb022d675 100644
--- a/clang/lib/AST/Interp/Interp.cpp
+++ b/clang/lib/AST/Interp/Interp.cpp
@@ -872,7 +872,7 @@ static bool runRecordDestructor(InterpState &S, CodePtr OpPC,
       return false;
 
     S.Stk.push<Pointer>(BasePtr);
-    if (!Call(S, OpPC, DtorFunc, 0))
+    if (!Call(S, OpPC, DtorFunc, 0, 0))
       return false;
   }
 
diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h
index 2eed0d3d1f16b..5a0f1de1140aa 100644
--- a/clang/lib/AST/Interp/Interp.h
+++ b/clang/lib/AST/Interp/Interp.h
@@ -2513,7 +2513,7 @@ inline bool ArrayDecay(InterpState &S, CodePtr OpPC) {
 }
 
 inline bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func,
-                    uint32_t VarArgSize) {
+                    uint32_t VarArgSize, const Expr *CE) {
   if (Func->hasThisPointer()) {
     size_t ArgSize = Func->getArgSize() + VarArgSize;
     size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);
@@ -2540,7 +2540,7 @@ inline bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func,
   if (!CheckCallDepth(S, OpPC))
     return false;
 
-  auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC, VarArgSize);
+  auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC, CE, VarArgSize);
   InterpFrame *FrameBefore = S.Current;
   S.Current = NewFrame.get();
 
@@ -2563,7 +2563,7 @@ inline bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func,
 }
 
 inline bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
-                 uint32_t VarArgSize) {
+                 uint32_t VarArgSize, const Expr *CE) {
   if (Func->hasThisPointer()) {
     size_t ArgSize = Func->getArgSize() + VarArgSize;
     size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);
@@ -2591,7 +2591,7 @@ inline bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
   if (!CheckCallDepth(S, OpPC))
     return false;
 
-  auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC, VarArgSize);
+  auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC, CE, VarArgSize);
   InterpFrame *FrameBefore = S.Current;
   S.Current = NewFrame.get();
 
@@ -2612,7 +2612,7 @@ inline bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
 }
 
 inline bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,
-                     uint32_t VarArgSize) {
+                     uint32_t VarArgSize, const Expr *CE) {
   assert(Func->hasThisPointer());
   assert(Func->isVirtual());
   size_t ArgSize = Func->getArgSize() + VarArgSize;
@@ -2659,7 +2659,7 @@ inline bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,
     }
   }
 
-  if (!Call(S, OpPC, Func, VarArgSize))
+  if (!Call(S, OpPC, Func, VarArgSize, CE))
     return false;
 
   // Covariant return types. The return type of Overrider is a pointer
@@ -2686,7 +2686,7 @@ inline bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,
 
 inline bool CallBI(InterpState &S, CodePtr &PC, const Function *Func,
                    const CallExpr *CE) {
-  auto NewFrame = std::make_unique<InterpFrame>(S, Func, PC);
+  auto NewFrame = std::make_unique<InterpFrame>(S, Func, PC, CE);
 
   InterpFrame *FrameBefore = S.Current;
   S.Current = NewFrame.get();
@@ -2737,9 +2737,9 @@ inline bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize,
     VarArgSize -= align(primSize(PT_Ptr));
 
   if (F->isVirtual())
-    return CallVirt(S, OpPC, F, VarArgSize);
+    return CallVirt(S, OpPC, F, VarArgSize, CE);
 
-  return Call(S, OpPC, F, VarArgSize);
+  return Call(S, OpPC, F, VarArgSize, CE);
 }
 
 inline bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func) {
diff --git a/clang/lib/AST/Interp/InterpFrame.cpp b/clang/lib/AST/Interp/InterpFrame.cpp
index 83784db91f4f3..b6352b200e55f 100644
--- a/clang/lib/AST/Interp/InterpFrame.cpp
+++ b/clang/lib/AST/Interp/InterpFrame.cpp
@@ -18,15 +18,17 @@
 #include "Program.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/DeclCXX.h"
+#include "clang/AST/ExprCXX.h"
 
 using namespace clang;
 using namespace clang::interp;
 
 InterpFrame::InterpFrame(InterpState &S, const Function *Func,
-                         InterpFrame *Caller, CodePtr RetPC, unsigned ArgSize)
+                         InterpFrame *Caller, CodePtr RetPC, unsigned ArgSize,
+                         const clang::Expr *CE)
     : Caller(Caller), S(S), Depth(Caller ? Caller->Depth + 1 : 0), Func(Func),
-      RetPC(RetPC), ArgSize(ArgSize), Args(static_cast<char *>(S.Stk.top())),
-      FrameOffset(S.Stk.size()) {
+      CallExpr(CE), RetPC(RetPC), ArgSize(ArgSize),
+      Args(static_cast<char *>(S.Stk.top())), FrameOffset(S.Stk.size()) {
   if (!Func)
     return;
 
@@ -46,8 +48,9 @@ InterpFrame::InterpFrame(InterpState &S, const Function *Func,
 }
 
 InterpFrame::InterpFrame(InterpState &S, const Function *Func, CodePtr RetPC,
-                         unsigned VarArgSize)
-    : InterpFrame(S, Func, S.Current, RetPC, Func->getArgSize() + VarArgSize) {
+                         const clang::Expr *CE, unsigned VarArgSize)
+    : InterpFrame(S, Func, S.Current, RetPC, Func->getArgSize() + VarArgSize,
+                  CE) {
   // As per our calling convention, the this pointer is
   // part of the ArgSize.
   // If the function has RVO, the RVO pointer is first.
@@ -170,10 +173,26 @@ void InterpFrame::describe(llvm::raw_ostream &OS) const {
     return;
 
   const FunctionDecl *F = getCallee();
-  if (const auto *M = dyn_cast<CXXMethodDecl>(F);
-      M && M->isInstance() && !isa<CXXConstructorDecl>(F)) {
-    print(OS, This, S.getCtx(), S.getCtx().getRecordType(M->getParent()));
-    OS << "->";
+  if (const auto *MCE = dyn_cast_if_present<CXXMemberCallExpr>(CallExpr)) {
+    const Expr *Object = MCE->getImplicitObjectArgument();
+    Object->printPretty(OS, /*Helper=*/nullptr, S.getCtx().getPrintingPolicy(),
+                        /*Indentation=*/0);
+    if (Object->getType()->isPointerType())
+      OS << "->";
+    else
+      OS << ".";
+  } else if (const auto *OCE =
+                 dyn_cast_if_present<CXXOperatorCallExpr>(CallExpr)) {
+    OCE->getArg(0)->printPretty(OS, /*Helper=*/nullptr,
+                                S.getCtx().getPrintingPolicy(),
+                                /*Indentation=*/0);
+    OS << ".";
+  } else {
+    if (const auto *M = dyn_cast<CXXMethodDecl>(F);
+        M && M->isInstance() && !isa<CXXConstructorDecl>(F)) {
+      print(OS, This, S.getCtx(), S.getCtx().getRecordType(M->getParent()));
+      OS << "->";
+    }
   }
 
   F->getNameForDiagnostic(OS, S.getCtx().getPrintingPolicy(),
diff --git a/clang/lib/AST/Interp/InterpFrame.h b/clang/lib/AST/Interp/InterpFrame.h
index 91b9b41b5d334..c8f492b0b5217 100644
--- a/clang/lib/AST/Interp/InterpFrame.h
+++ b/clang/lib/AST/Interp/InterpFrame.h
@@ -30,14 +30,14 @@ class InterpFrame final : public Frame {
 
   /// Creates a new frame for a method call.
   InterpFrame(InterpState &S, const Function *Func, InterpFrame *Caller,
-              CodePtr RetPC, unsigned ArgSize);
+              CodePtr RetPC, unsigned ArgSize, const Expr *CE);
 
   /// Creates a new frame with the values that make sense.
   /// I.e., the caller is the current frame of S,
   /// the This() pointer is the current Pointer on the top of S's stack,
   /// and the RVO pointer is before that.
   InterpFrame(InterpState &S, const Function *Func, CodePtr RetPC,
-              unsigned VarArgSize = 0);
+              const Expr *CE, unsigned VarArgSize = 0);
 
   /// Destroys the frame, killing all live pointers to stack slots.
   ~InterpFrame();
@@ -152,6 +152,8 @@ class InterpFrame final : public Frame {
   unsigned Depth;
   /// Reference to the function being executed.
   const Function *Func;
+  /// The syntactical structure of member function calls
+  const Expr *CallExpr;
   /// Current object pointer for methods.
   Pointer This;
   /// Pointer the non-primitive return value gets constructed in.
diff --git a/clang/lib/AST/Interp/Opcodes.td b/clang/lib/AST/Interp/Opcodes.td
index 220dff0c556b1..9aabd9198f129 100644
--- a/clang/lib/AST/Interp/Opcodes.td
+++ b/clang/lib/AST/Interp/Opcodes.td
@@ -198,11 +198,11 @@ def NoRet : Opcode {}
 
 
 def Call : Opcode {
-  let Args = [ArgFunction, ArgUint32];
+  let Args = [ArgFunction, ArgUint32, ArgExpr];
 }
 
 def CallVirt : Opcode {
-  let Args = [ArgFunction, ArgUint32];
+  let Args = [ArgFunction, ArgUint32, ArgExpr];
 }
 
 def CallBI : Opcode {
@@ -214,7 +214,7 @@ def CallPtr : Opcode {
 }
 
 def CallVar : Opcode {
-  let Args = [ArgFunction, ArgUint32];
+  let Args = [ArgFunction, ArgUint32, ArgExpr];
 }
 
 def OffsetOf : Opcode {
diff --git a/clang/test/AST/Interp/constexpr-nqueens.cpp b/clang/test/AST/Interp/constexpr-nqueens.cpp
index 971f99a032b66..ed038dbc9b077 100644
--- a/clang/test/AST/Interp/constexpr-nqueens.cpp
+++ b/clang/test/AST/Interp/constexpr-nqueens.cpp
@@ -49,7 +49,7 @@ constexpr Board buildBoardScan(int N, int Col, int Row, const Board &B) {
   return Row == N ? Board(0, true) :
          B.ok(Row, Col) ?
          tryBoard(buildBoardRecurse(N, Col + 1, B.addQueen(Row, Col)), // ref-note {{in call to 'B.addQueen(0, 0)}} \
-                                                                       // expected-note {{in call to '&Board()->addQueen(0, 0)}}
+                                                                       // expected-note {{in call to 'B.addQueen(0, 0)}}
                   N, Col, Row+1, B) :
          buildBoardScan(N, Col, Row + 1, B);
 }
diff --git a/clang/test/AST/Interp/lambda.cpp b/clang/test/AST/Interp/lambda.cpp
index d68fe995e8fa1..27bbebddf4480 100644
--- a/clang/test/AST/Interp/lambda.cpp
+++ b/clang/test/AST/Interp/lambda.cpp
@@ -46,7 +46,7 @@ constexpr int div(int a, int b) {
     return a / b; // both-note {{division by zero}}
   };
 
-  return f(); // expected-note {{in call to '&f->operator()()'}} \
+  return f(); // expected-note {{in call to 'f.operator()()'}} \
               // ref-note {{in call to 'f.operator()()'}}
 }
 static_assert(div(8, 2) == 4);
diff --git a/clang/test/AST/Interp/records.cpp b/clang/test/AST/Interp/records.cpp
index 479c0487fecae..0735d4765a22a 100644
--- a/clang/test/AST/Interp/records.cpp
+++ b/clang/test/AST/Interp/records.cpp
@@ -335,7 +335,7 @@ namespace InitializerTemporaries {
 
   constexpr int f() {
     S{}; // ref-note {{in call to 'S{}.~S()'}} \
-         // expected-note {{in call to '&S{}->~S()'}}
+         // expected-note {{in call to '~S()'}}
     return 12;
   }
   static_assert(f() == 12); // both-error {{not an integral constant expression}} \
@@ -599,7 +599,7 @@ namespace Destructors {
   };
   constexpr int testS() {
     S{}; // ref-note {{in call to 'S{}.~S()'}} \
-         // expected-note {{in call to '&S{}->~S()'}}
+         // expected-note {{in call to '~S()'}}
     return 1;
   }
   static_assert(testS() == 1); // both-error {{not an integral constant expression}} \



More information about the cfe-commits mailing list