Index: clang/lib/AST/Interp/ByteCodeExprGen.h =================================================================== --- clang/lib/AST/Interp/ByteCodeExprGen.h +++ clang/lib/AST/Interp/ByteCodeExprGen.h @@ -92,6 +92,8 @@ bool VisitAbstractConditionalOperator(const AbstractConditionalOperator *E); bool VisitStringLiteral(const StringLiteral *E); bool VisitCharacterLiteral(const CharacterLiteral *E); + bool VisitExprWithCleanups(const ExprWithCleanups *E); + bool VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *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 @@ -468,6 +468,57 @@ return this->emitConst(E, E->getValue()); } +template +bool ByteCodeExprGen::VisitExprWithCleanups( + const ExprWithCleanups *E) { + const Expr *SubExpr = E->getSubExpr(); + + assert(E->getNumObjects() == 0 && "TODO: Implement cleanups"); + return this->visit(SubExpr); +} + +template +bool ByteCodeExprGen::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(); + Optional SubExprT = classify(SubExpr); + // FIXME: Implement this for records and arrays as well. + if (!SubExprT) + return false; + + if (SD == SD_Static) { + if (Optional 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 (Optional LocalIndex = + allocateLocalPrimitive(SubExpr, *SubExprT, true, true)) { + if (!this->visitInitializer(SubExpr)) + return false; + + if (!this->emitSetLocal(PT_Sint32, *LocalIndex, E)) + return false; + return this->emitGetPtrLocal(*LocalIndex, E); + } + } + + return false; +} + template bool ByteCodeExprGen::discard(const Expr *E) { OptionScope Scope(this, /*NewDiscardResult=*/true); return this->Visit(E); Index: clang/lib/AST/Interp/Interp.h =================================================================== --- clang/lib/AST/Interp/Interp.h +++ clang/lib/AST/Interp/Interp.h @@ -568,6 +568,22 @@ 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 ::T> +bool InitGlobalTemp(InterpState &S, CodePtr OpPC, uint32_t I, + const LifetimeExtendedTemporaryDecl *Temp) { + assert(Temp); + const T Value = S.Stk.peek(); + APValue APV = Value.toAPValue(); + APValue *Cached = Temp->getOrCreateValue(true); + *Cached = APV; + + S.P.getGlobal(I)->deref() = S.Stk.pop(); + return true; +} + template ::T> bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) { if (S.checkingPotentialConstantExpression()) Index: clang/lib/AST/Interp/Opcodes.td =================================================================== --- clang/lib/AST/Interp/Opcodes.td +++ clang/lib/AST/Interp/Opcodes.td @@ -48,6 +48,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 ArgLETD: ArgType { let Name = "const LifetimeExtendedTemporaryDecl *"; } //===----------------------------------------------------------------------===// // Classes of types instructions operate on. @@ -307,6 +308,10 @@ // [Value] -> [] def InitGlobal : AccessOpcode; // [Value] -> [] +def InitGlobalTemp : AccessOpcode { + let Args = [ArgUint32, ArgLETD]; +} +// [Value] -> [] def SetGlobal : AccessOpcode; // [] -> [Value] Index: clang/test/AST/Interp/references.cpp =================================================================== --- clang/test/AST/Interp/references.cpp +++ 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 @@ } 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;