tbaeder created this revision.
tbaeder added reviewers: aaron.ballman, erichkeane.
Herald added a project: All.
tbaeder requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

I wanted to do only pointers here, but they are impossible to test without 
having some support for DeclRefExprs.

This also implements assignments because that was broken when implementing 
DeclRefExprs. Assignments were handled through `LValueToRValue` casts before.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D132111

Files:
  clang/lib/AST/Interp/ByteCodeExprGen.cpp
  clang/lib/AST/Interp/ByteCodeExprGen.h
  clang/test/AST/Interp/cxx20.cpp
  clang/test/AST/Interp/literals.cpp

Index: clang/test/AST/Interp/literals.cpp
===================================================================
--- clang/test/AST/Interp/literals.cpp
+++ clang/test/AST/Interp/literals.cpp
@@ -32,3 +32,12 @@
 static_assert(!0, "");
 static_assert(-true, "");
 static_assert(-false, ""); //expected-error{{failed}}
+
+constexpr int m = 10;
+constexpr const int *p = &m;
+static_assert(p != nullptr, "");
+static_assert(*p == 10, "");
+
+constexpr const int* getIntPointer() {
+  return &m;
+}
Index: clang/test/AST/Interp/cxx20.cpp
===================================================================
--- /dev/null
+++ clang/test/AST/Interp/cxx20.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++20 -verify %s
+// RUN: %clang_cc1 -std=c++20 -verify %s -DREFERENCE
+
+
+// expected-no-diagnostics
+constexpr int getMinus5() {
+  int a = 10;
+  a = -5;
+  int *p = &a;
+  return *p;
+}
+
Index: clang/lib/AST/Interp/ByteCodeExprGen.h
===================================================================
--- clang/lib/AST/Interp/ByteCodeExprGen.h
+++ clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -72,6 +72,7 @@
   bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E);
   bool VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E);
   bool VisitUnaryOperator(const UnaryOperator *E);
+  bool VisitDeclRefExpr(const DeclRefExpr *E);
 
 protected:
   bool visitExpr(const Expr *E) override;
Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp
===================================================================
--- clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -98,11 +98,15 @@
           // Value loaded - nothing to do here.
           return true;
         },
-        [this, CE](PrimType T) {
-          // Pointer on stack - dereference it.
-          if (!this->emitLoadPop(T, CE))
-            return false;
-          return DiscardResult ? this->emitPop(T, CE) : true;
+        [this, CE, SubExpr](PrimType T) {
+          // DeclRefExpr are modeled as pointers, so nothing to do.
+          if (isa<DeclRefExpr>(SubExpr->IgnoreImpCasts())) {
+            // Pointer on stack - dereference it.
+            if (!this->emitLoadPop(T, CE))
+              return false;
+            return DiscardResult ? this->emitPop(T, CE) : true;
+          }
+          return true;
         });
   }
 
@@ -209,6 +213,12 @@
       return Discard(this->emitAdd(*T, BO));
     case BO_Mul:
       return Discard(this->emitMul(*T, BO));
+    case BO_Assign:
+      if (!this->emitStore(*T, BO))
+        return false;
+      // TODO: Assignments return the assigned value, so the pop() here
+      //   should proably just go away.
+      return this->emitPopPtr(BO);
     default:
       return this->bail(BO);
     }
@@ -596,8 +606,7 @@
 
 template <class Emitter>
 bool ByteCodeExprGen<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
-  if (!this->Visit(E->getSubExpr()))
-    return false;
+  const Expr *SubExpr = E->getSubExpr();
 
   switch (E->getOpcode()) {
   case UO_PostInc: // x++
@@ -607,16 +616,37 @@
     return false;
 
   case UO_LNot: // !x
+    if (!this->Visit(SubExpr))
+      return false;
     return this->emitInvBool(E);
   case UO_Minus: // -x
+    if (!this->Visit(SubExpr))
+      return false;
     if (Optional<PrimType> T = classify(E->getType()))
       return this->emitNeg(*T, E);
     return false;
   case UO_Plus:  // +x
-    return true; // noop
+    return this->Visit(SubExpr); // noop
 
   case UO_AddrOf: // &x
+    // We should already have a pointer when we get here.
+    return this->Visit(SubExpr);
+
   case UO_Deref:  // *x
+    return dereference(
+        SubExpr, DerefKind::Read,
+        [](PrimType) {
+          llvm_unreachable("Referencing requires a pointer");
+          return false;
+        },
+        [this, E](PrimType T) {
+          // T: type we get here from classify() is the subexpr
+          // TODO: Is this right?
+          T = *classify(E->getType());
+          if (!this->emitLoadPop(T, E))
+            return false;
+          return DiscardResult ? this->emitPop(T, E) : true;
+        });
   case UO_Not:    // ~x
   case UO_Real:   // __real x
   case UO_Imag:   // __imag x
@@ -628,6 +658,24 @@
   return false;
 }
 
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitDeclRefExpr(const DeclRefExpr *E) {
+  if (auto It = Locals.find(E->getDecl()); It != Locals.end()) {
+    const unsigned Offset = It->second.Offset;
+    return this->emitGetPtrLocal(Offset, E);
+  } else if (auto GlobalIndex = P.getGlobal(E->getDecl())) {
+    return this->emitGetPtrGlobal(*GlobalIndex, E);
+  } else if (isa<ParmVarDecl>(E->getDecl())) {
+    // I'm pretty sure we should do something here, BUT
+    // when we're in evaluateAsRValue(), we don't have any parameters,
+    // so we can't actually use this->Params. This happens when
+    // a parameter is used in a return statement.
+    return false;
+  }
+
+  return false;
+}
+
 template <class Emitter>
 void ByteCodeExprGen<Emitter>::emitCleanup() {
   for (VariableScope<Emitter> *C = VarScope; C; C = C->getParent())
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to