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(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 bool ByteCodeExprGen::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 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 +bool ByteCodeExprGen::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(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 void ByteCodeExprGen::emitCleanup() { for (VariableScope *C = VarScope; C; C = C->getParent()) 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/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; +}