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