Implement MaterializeTemporaryExpr for primitive types.
Differential Revision: https://reviews.llvm.org/D136017
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;
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;
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())
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.
// [Value] -> []
def InitGlobal : AccessOpcode;
// [Value] -> []
+def InitGlobalTemp : AccessOpcode {
+ let Args = [ArgUint32, ArgLETD];
+}
+// [Value] -> []
def SetGlobal : AccessOpcode;
// [] -> [Value]
// RUN: %clang_cc1 -verify=ref %s
-// ref-no-diagnostics
-
constexpr int a = 10;
constexpr const int &b = a;
static_assert(a == b, "");
}
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;