Author: Timm Bäder Date: 2023-02-03T15:11:15+01:00 New Revision: 7bb615ea0ec015eb5991ddc00e0a3fc31cb2735e
URL: https://github.com/llvm/llvm-project/commit/7bb615ea0ec015eb5991ddc00e0a3fc31cb2735e DIFF: https://github.com/llvm/llvm-project/commit/7bb615ea0ec015eb5991ddc00e0a3fc31cb2735e.diff LOG: [clang][Interp] Materializing primitive temporaries Implement MaterializeTemporaryExpr for primitive types. Differential Revision: https://reviews.llvm.org/D136017 Added: Modified: clang/lib/AST/Interp/ByteCodeExprGen.cpp clang/lib/AST/Interp/ByteCodeExprGen.h clang/lib/AST/Interp/Interp.h clang/lib/AST/Interp/Opcodes.td clang/test/AST/Interp/references.cpp Removed: ################################################################################ diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp index 4c3b6f59a3016..b02e3ae02ae7c 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -782,6 +782,57 @@ bool ByteCodeExprGen<Emitter>::VisitCompoundAssignOperator( return this->emitStore(*ResultT, E); } +template <class Emitter> +bool ByteCodeExprGen<Emitter>::VisitExprWithCleanups( + const ExprWithCleanups *E) { + const Expr *SubExpr = E->getSubExpr(); + + assert(E->getNumObjects() == 0 && "TODO: Implement cleanups"); + return this->visit(SubExpr); +} + +template <class Emitter> +bool ByteCodeExprGen<Emitter>::VisitMaterializeTemporaryExpr( + const MaterializeTemporaryExpr *E) { + StorageDuration SD = E->getStorageDuration(); + + // We conservatively only support these for now. + if (SD != SD_Static && SD != SD_Automatic) + return false; + + const Expr *SubExpr = E->getSubExpr(); + std::optional<PrimType> SubExprT = classify(SubExpr); + // FIXME: Implement this for records and arrays as well. + if (!SubExprT) + return false; + + if (SD == SD_Static) { + if (std::optional<unsigned> GlobalIndex = P.createGlobal(E)) { + const LifetimeExtendedTemporaryDecl *TempDecl = + E->getLifetimeExtendedTemporaryDecl(); + + if (!this->visitInitializer(SubExpr)) + return false; + + if (!this->emitInitGlobalTemp(*SubExprT, *GlobalIndex, TempDecl, E)) + return false; + return this->emitGetPtrGlobal(*GlobalIndex, E); + } + } else if (SD == SD_Automatic) { + if (std::optional<unsigned> LocalIndex = + allocateLocalPrimitive(SubExpr, *SubExprT, true, true)) { + if (!this->visitInitializer(SubExpr)) + return false; + + if (!this->emitSetLocal(*SubExprT, *LocalIndex, E)) + return false; + return this->emitGetPtrLocal(*LocalIndex, E); + } + } + + return false; +} + template <class Emitter> bool ByteCodeExprGen<Emitter>::discard(const Expr *E) { if (E->containsErrors()) return false; diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h index 0a64ff3513dd8..540b9ec2f3d46 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.h +++ b/clang/lib/AST/Interp/ByteCodeExprGen.h @@ -87,6 +87,8 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>, bool VisitCharacterLiteral(const CharacterLiteral *E); bool VisitCompoundAssignOperator(const CompoundAssignOperator *E); bool VisitFloatCompoundAssignOperator(const CompoundAssignOperator *E); + bool VisitExprWithCleanups(const ExprWithCleanups *E); + bool VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *E); protected: bool visitExpr(const Expr *E) override; diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h index b35cc017d3d70..99c1bd58acd25 100644 --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -818,6 +818,22 @@ bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) { return true; } +/// 1) Converts the value on top of the stack to an APValue +/// 2) Sets that APValue on \Temp +/// 3) Initialized global with index \I with that +template <PrimType Name, class T = typename PrimConv<Name>::T> +bool InitGlobalTemp(InterpState &S, CodePtr OpPC, uint32_t I, + const LifetimeExtendedTemporaryDecl *Temp) { + assert(Temp); + const T Value = S.Stk.peek<T>(); + APValue APV = Value.toAPValue(); + APValue *Cached = Temp->getOrCreateValue(true); + *Cached = APV; + + S.P.getGlobal(I)->deref<T>() = S.Stk.pop<T>(); + return true; +} + template <PrimType Name, class T = typename PrimConv<Name>::T> bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) { if (S.checkingPotentialConstantExpression()) diff --git a/clang/lib/AST/Interp/Opcodes.td b/clang/lib/AST/Interp/Opcodes.td index 8b49fb4e61b1b..d1ad7adc1edc6 100644 --- a/clang/lib/AST/Interp/Opcodes.td +++ b/clang/lib/AST/Interp/Opcodes.td @@ -49,6 +49,7 @@ def ArgRecordDecl : ArgType { let Name = "const RecordDecl *"; } def ArgRecordField : ArgType { let Name = "const Record::Field *"; } def ArgFltSemantics : ArgType { let Name = "const llvm::fltSemantics *"; } def ArgRoundingMode : ArgType { let Name = "llvm::RoundingMode"; } +def ArgLETD: ArgType { let Name = "const LifetimeExtendedTemporaryDecl *"; } //===----------------------------------------------------------------------===// // Classes of types instructions operate on. @@ -332,6 +333,10 @@ def GetGlobal : AccessOpcode; // [Value] -> [] def InitGlobal : AccessOpcode; // [Value] -> [] +def InitGlobalTemp : AccessOpcode { + let Args = [ArgUint32, ArgLETD]; +} +// [Value] -> [] def SetGlobal : AccessOpcode; // [] -> [Value] diff --git a/clang/test/AST/Interp/references.cpp b/clang/test/AST/Interp/references.cpp index 0e6d5532ba0e8..5dc6067db6a64 100644 --- a/clang/test/AST/Interp/references.cpp +++ b/clang/test/AST/Interp/references.cpp @@ -2,8 +2,6 @@ // RUN: %clang_cc1 -verify=ref %s -// ref-no-diagnostics - constexpr int a = 10; constexpr const int &b = a; static_assert(a == b, ""); @@ -71,9 +69,22 @@ constexpr int testGetValue() { } static_assert(testGetValue() == 30, ""); -// FIXME: ExprWithCleanups + MaterializeTemporaryExpr not implemented -constexpr const int &MCE = 1; // expected-error{{must be initialized by a constant expression}} +constexpr const int &MCE = 20; +static_assert(MCE == 20, ""); +static_assert(MCE == 30, ""); // expected-error {{static assertion failed}} \ + // expected-note {{evaluates to '20 == 30'}} \ + // ref-error {{static assertion failed}} \ + // ref-note {{evaluates to '20 == 30'}} +constexpr int LocalMCE() { + const int &m = 100; + return m; +} +static_assert(LocalMCE() == 100, ""); +static_assert(LocalMCE() == 200, ""); // expected-error {{static assertion failed}} \ + // expected-note {{evaluates to '100 == 200'}} \ + // ref-error {{static assertion failed}} \ + // ref-note {{evaluates to '100 == 200'}} struct S { int i, j; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits