Index: include/clang/AST/APValue.h =================================================================== --- include/clang/AST/APValue.h +++ include/clang/AST/APValue.h @@ -53,7 +53,58 @@ MemberPointer, AddrLabelDiff }; - typedef llvm::PointerUnion LValueBase; + + class LValueBase { + public: + typedef llvm::PointerUnion PtrTy; + + LValueBase() : CallIndex(0), Version(0) {} + + template + LValueBase(T P, unsigned I = 0, unsigned V = 0) + : Ptr(P), CallIndex(I), Version(V) {} + + template + bool is() const { return Ptr.is(); } + + template + T get() const { return Ptr.get(); } + + template + T dyn_cast() const { return Ptr.dyn_cast(); } + + void *getOpaqueValue() const; + + bool isNull() const; + + explicit operator bool () const; + + PtrTy getPointer() const { + return Ptr; + } + + unsigned getCallIndex() const { + return CallIndex; + } + + void setCallIndex(unsigned Index) { + CallIndex = Index; + } + + unsigned getVersion() const { + return Version; + } + + bool operator==(const LValueBase &Other) const { + return Ptr == Other.Ptr && CallIndex == Other.CallIndex && + Version == Other.Version; + } + + private: + PtrTy Ptr; + unsigned CallIndex, Version; + }; + typedef llvm::PointerIntPair BaseOrMemberType; union LValuePathEntry { /// BaseOrMember - The FieldDecl or CXXRecordDecl indicating the next item @@ -135,15 +186,15 @@ } APValue(const APValue &RHS); APValue(APValue &&RHS) : Kind(Uninitialized) { swap(RHS); } - APValue(LValueBase B, const CharUnits &O, NoLValuePath N, unsigned CallIndex, + APValue(LValueBase B, const CharUnits &O, NoLValuePath N, bool IsNullPtr = false) : Kind(Uninitialized) { - MakeLValue(); setLValue(B, O, N, CallIndex, IsNullPtr); + MakeLValue(); setLValue(B, O, N, IsNullPtr); } APValue(LValueBase B, const CharUnits &O, ArrayRef Path, - bool OnePastTheEnd, unsigned CallIndex, bool IsNullPtr = false) + bool OnePastTheEnd, bool IsNullPtr = false) : Kind(Uninitialized) { - MakeLValue(); setLValue(B, O, Path, OnePastTheEnd, CallIndex, IsNullPtr); + MakeLValue(); setLValue(B, O, Path, OnePastTheEnd, IsNullPtr); } APValue(UninitArray, unsigned InitElts, unsigned Size) : Kind(Uninitialized) { MakeArray(InitElts, Size); @@ -255,6 +306,7 @@ bool hasLValuePath() const; ArrayRef getLValuePath() const; unsigned getLValueCallIndex() const; + unsigned getLValueVersion() const; bool isNullPointer() const; APValue &getVectorElt(unsigned I) { @@ -376,10 +428,10 @@ ((ComplexAPFloat *)(char *)Data.buffer)->Imag = std::move(I); } void setLValue(LValueBase B, const CharUnits &O, NoLValuePath, - unsigned CallIndex, bool IsNullPtr); + bool IsNullPtr); void setLValue(LValueBase B, const CharUnits &O, ArrayRef Path, bool OnePastTheEnd, - unsigned CallIndex, bool IsNullPtr); + bool IsNullPtr); void setUnion(const FieldDecl *Field, const APValue &Value) { assert(isUnion() && "Invalid accessor"); ((UnionData*)(char*)Data.buffer)->Field = Field; @@ -451,4 +503,14 @@ } // end namespace clang. +namespace llvm { +template<> struct DenseMapInfo { + static clang::APValue::LValueBase getEmptyKey(); + static clang::APValue::LValueBase getTombstoneKey(); + static unsigned getHashValue(const clang::APValue::LValueBase &Base); + static bool isEqual(const clang::APValue::LValueBase &LHS, + const clang::APValue::LValueBase &RHS); +}; +} + #endif Index: lib/AST/APValue.cpp =================================================================== --- lib/AST/APValue.cpp +++ lib/AST/APValue.cpp @@ -23,14 +23,57 @@ namespace { struct LVBase { - llvm::PointerIntPair BaseAndIsOnePastTheEnd; + APValue::LValueBase Base; CharUnits Offset; unsigned PathLength; - unsigned CallIndex; - bool IsNullPtr; + bool IsNullPtr : 1; + bool IsOnePastTheEnd : 1; }; } +void *APValue::LValueBase::getOpaqueValue() const { + return Ptr.getOpaqueValue(); +} + +bool APValue::LValueBase::isNull() const { + return Ptr.isNull(); +} + +APValue::LValueBase::operator bool () const { + return static_cast(Ptr); +} + +clang::APValue::LValueBase +llvm::DenseMapInfo::getEmptyKey() { + return clang::APValue::LValueBase( + DenseMapInfo::getEmptyKey(), + DenseMapInfo::getEmptyKey(), + DenseMapInfo::getEmptyKey()); +} + +clang::APValue::LValueBase +llvm::DenseMapInfo::getTombstoneKey() { + return clang::APValue::LValueBase( + DenseMapInfo::getTombstoneKey(), + DenseMapInfo::getTombstoneKey(), + DenseMapInfo::getTombstoneKey()); +} + +unsigned llvm::DenseMapInfo::getHashValue( + const clang::APValue::LValueBase &Base) { + llvm::FoldingSetNodeID ID; + ID.AddPointer(Base.getOpaqueValue()); + ID.AddInteger(Base.getCallIndex()); + ID.AddInteger(Base.getVersion()); + return ID.ComputeHash(); +} + +bool llvm::DenseMapInfo::isEqual( + const clang::APValue::LValueBase &LHS, + const clang::APValue::LValueBase &RHS) { + return LHS == RHS; +} + struct APValue::LV : LVBase { static const unsigned InlinePathSpace = (DataSize - sizeof(LVBase)) / sizeof(LValuePathEntry); @@ -150,11 +193,10 @@ MakeLValue(); if (RHS.hasLValuePath()) setLValue(RHS.getLValueBase(), RHS.getLValueOffset(), RHS.getLValuePath(), - RHS.isLValueOnePastTheEnd(), RHS.getLValueCallIndex(), - RHS.isNullPointer()); + RHS.isLValueOnePastTheEnd(), RHS.isNullPointer()); else setLValue(RHS.getLValueBase(), RHS.getLValueOffset(), NoLValuePath(), - RHS.getLValueCallIndex(), RHS.isNullPointer()); + RHS.isNullPointer()); break; case Array: MakeArray(RHS.getArrayInitializedElts(), RHS.getArraySize()); @@ -552,12 +594,12 @@ const APValue::LValueBase APValue::getLValueBase() const { assert(isLValue() && "Invalid accessor"); - return ((const LV*)(const void*)Data.buffer)->BaseAndIsOnePastTheEnd.getPointer(); + return ((const LV*)(const void*)Data.buffer)->Base; } bool APValue::isLValueOnePastTheEnd() const { assert(isLValue() && "Invalid accessor"); - return ((const LV*)(const void*)Data.buffer)->BaseAndIsOnePastTheEnd.getInt(); + return ((const LV*)(const void*)Data.buffer)->IsOnePastTheEnd; } CharUnits &APValue::getLValueOffset() { @@ -578,7 +620,12 @@ unsigned APValue::getLValueCallIndex() const { assert(isLValue() && "Invalid accessor"); - return ((const LV*)(const char*)Data.buffer)->CallIndex; + return ((const LV*)(const char*)Data.buffer)->Base.getCallIndex(); +} + +unsigned APValue::getLValueVersion() const { + assert(isLValue() && "Invalid accessor"); + return ((const LV*)(const char*)Data.buffer)->Base.getVersion(); } bool APValue::isNullPointer() const { @@ -587,26 +634,24 @@ } void APValue::setLValue(LValueBase B, const CharUnits &O, NoLValuePath, - unsigned CallIndex, bool IsNullPtr) { + bool IsNullPtr) { assert(isLValue() && "Invalid accessor"); LV &LVal = *((LV*)(char*)Data.buffer); - LVal.BaseAndIsOnePastTheEnd.setPointer(B); - LVal.BaseAndIsOnePastTheEnd.setInt(false); + LVal.Base = B; + LVal.IsOnePastTheEnd = false; LVal.Offset = O; - LVal.CallIndex = CallIndex; LVal.resizePath((unsigned)-1); LVal.IsNullPtr = IsNullPtr; } void APValue::setLValue(LValueBase B, const CharUnits &O, ArrayRef Path, bool IsOnePastTheEnd, - unsigned CallIndex, bool IsNullPtr) { + bool IsNullPtr) { assert(isLValue() && "Invalid accessor"); LV &LVal = *((LV*)(char*)Data.buffer); - LVal.BaseAndIsOnePastTheEnd.setPointer(B); - LVal.BaseAndIsOnePastTheEnd.setInt(IsOnePastTheEnd); + LVal.Base = B; + LVal.IsOnePastTheEnd = IsOnePastTheEnd; LVal.Offset = O; - LVal.CallIndex = CallIndex; LVal.resizePath(Path.size()); memcpy(LVal.getPath(), Path.data(), Path.size() * sizeof(LValuePathEntry)); LVal.IsNullPtr = IsNullPtr; Index: lib/AST/ExprConstant.cpp =================================================================== --- lib/AST/ExprConstant.cpp +++ lib/AST/ExprConstant.cpp @@ -438,8 +438,8 @@ // Note that we intentionally use std::map here so that references to // values are stable. - typedef std::map MapTy; - typedef MapTy::const_iterator temp_iterator; + typedef std::map VersionToValueMap; + typedef std::map MapTy; /// Temporaries - Temporary lvalues materialized within this stack frame. MapTy Temporaries; @@ -449,6 +449,20 @@ /// Index - The call index of this call. unsigned Index; + /// The stack of integers for tracking version numbers for temporaries. + SmallVector TempVersionStack = {1}; + unsigned CurTempVersion = TempVersionStack.back(); + + unsigned getTempVersion() const { return TempVersionStack.back(); } + + void pushTempVersion() { + TempVersionStack.push_back(++CurTempVersion); + } + + void popTempVersion() { + TempVersionStack.pop_back(); + } + // FIXME: Adding this to every 'CallStackFrame' may have a nontrivial impact // on the overall stack usage of deeply-recursing constexpr evaluataions. // (We should cache this map rather than recomputing it repeatedly.) @@ -465,10 +479,36 @@ APValue *Arguments); ~CallStackFrame(); - APValue *getTemporary(const void *Key) { + // Return the temporary for Key whose version number is Version. + APValue *getTemporary(const void *Key, unsigned Version) { + MapTy::iterator I = Temporaries.find(Key); + if (I == Temporaries.end()) + return nullptr; + // Return an uninitialized value if the temporary is not found. + static APValue UninitVal; + VersionToValueMap::iterator J = I->second.find(Version); + return J == I->second.end() ? &UninitVal : &J->second; + } + + // Return the current temporary for Key in the map. + APValue *getCurrentTemporary(const void *Key) { MapTy::iterator I = Temporaries.find(Key); - return I == Temporaries.end() ? nullptr : &I->second; + if (I == Temporaries.end()) + return nullptr; + // Return an uninitialized value if all temporaries for Key have been + // removed. + static APValue UninitVal; + return I->second.empty() ? &UninitVal : &I->second.rbegin()->second; } + + // Return the version number of the current temporary for Key. + unsigned getCurrentTemporaryVersion(const void *Key) const { + MapTy::const_iterator I = Temporaries.find(Key); + if (I == Temporaries.end() || I->second.empty()) + return 0; + return I->second.rbegin()->first; + } + APValue &createTemporary(const void *Key, bool IsLifetimeExtended); }; @@ -534,15 +574,20 @@ /// A cleanup, and a flag indicating whether it is lifetime-extended. class Cleanup { - llvm::PointerIntPair Value; + const void *Key; + unsigned Version; + std::pair, bool> Value; public: - Cleanup(APValue *Val, bool IsLifetimeExtended) - : Value(Val, IsLifetimeExtended) {} + Cleanup(const void *Key, unsigned Version, bool IsLifetimeExtended) + : Value({{Key, Version}, IsLifetimeExtended}) {} - bool isLifetimeExtended() const { return Value.getInt(); } - void endLifetime() { - *Value.getPointer() = APValue(); + bool isLifetimeExtended() const { return Value.second; } + + void endLifetime(CallStackFrame *F) { + // The temporary's lifetime has ended, so remove it from the map. + if (F) + F->Temporaries[Value.first.first].erase(Value.first.second); } }; @@ -598,7 +643,8 @@ /// EvaluatingObject - Pair of the AST node that an lvalue represents and /// the call index that that lvalue was allocated in. - typedef std::pair EvaluatingObject; + typedef std::pair> + EvaluatingObject; /// EvaluatingConstructors - Set of objects that are currently being /// constructed. @@ -617,8 +663,9 @@ } }; - bool isEvaluatingConstructor(APValue::LValueBase Decl, unsigned CallIndex) { - return EvaluatingConstructors.count(EvaluatingObject(Decl, CallIndex)); + bool isEvaluatingConstructor(APValue::LValueBase Decl, unsigned CallIndex, + unsigned Version) { + return EvaluatingConstructors.count(EvaluatingObject(Decl, {CallIndex, Version})); } /// The current array initialization index, if we're performing array @@ -714,7 +761,7 @@ void setEvaluatingDecl(APValue::LValueBase Base, APValue &Value) { EvaluatingDecl = Base; EvaluatingDeclValue = &Value; - EvaluatingConstructors.insert({Base, 0}); + EvaluatingConstructors.insert({Base, {0, 0}}); } const LangOptions &getLangOpts() const { return Ctx.getLangOpts(); } @@ -1078,11 +1125,16 @@ unsigned OldStackSize; public: ScopeRAII(EvalInfo &Info) - : Info(Info), OldStackSize(Info.CleanupStack.size()) {} + : Info(Info), OldStackSize(Info.CleanupStack.size()) { + // Push a new temporary version. This is needed to distinguish between + // temporaries created in different iterations of a loop. + Info.CurrentCall->pushTempVersion(); + } ~ScopeRAII() { // Body moved to a static method to encourage the compiler to inline away // instances of this class. cleanup(Info, OldStackSize); + Info.CurrentCall->popTempVersion(); } private: static void cleanup(EvalInfo &Info, unsigned OldStackSize) { @@ -1096,7 +1148,7 @@ ++NewEnd; } else { // End the lifetime of the object. - Info.CleanupStack[I].endLifetime(); + Info.CleanupStack[I].endLifetime(Info.CurrentCall); } } Info.CleanupStack.erase(Info.CleanupStack.begin() + NewEnd, @@ -1162,9 +1214,10 @@ APValue &CallStackFrame::createTemporary(const void *Key, bool IsLifetimeExtended) { - APValue &Result = Temporaries[Key]; + unsigned Version = Info.CurrentCall->getTempVersion(); + APValue &Result = Temporaries[Key][Version]; assert(Result.isUninit() && "temporary created multiple times"); - Info.CleanupStack.push_back(Cleanup(&Result, IsLifetimeExtended)); + Info.CleanupStack.push_back(Cleanup(Key, Version, IsLifetimeExtended)); return Result; } @@ -1254,27 +1307,27 @@ struct LValue { APValue::LValueBase Base; CharUnits Offset; - unsigned InvalidBase : 1; - unsigned CallIndex : 31; SubobjectDesignator Designator; - bool IsNullPtr; + bool IsNullPtr : 1; + bool InvalidBase : 1; const APValue::LValueBase getLValueBase() const { return Base; } CharUnits &getLValueOffset() { return Offset; } const CharUnits &getLValueOffset() const { return Offset; } - unsigned getLValueCallIndex() const { return CallIndex; } SubobjectDesignator &getLValueDesignator() { return Designator; } const SubobjectDesignator &getLValueDesignator() const { return Designator;} bool isNullPointer() const { return IsNullPtr;} + unsigned getLValueCallIndex() const { return Base.getCallIndex(); } + unsigned getLValueVersion() const { return Base.getVersion(); } + void moveInto(APValue &V) const { if (Designator.Invalid) - V = APValue(Base, Offset, APValue::NoLValuePath(), CallIndex, - IsNullPtr); + V = APValue(Base, Offset, APValue::NoLValuePath(), IsNullPtr); else { assert(!InvalidBase && "APValues can't handle invalid LValue bases"); V = APValue(Base, Offset, Designator.Entries, - Designator.IsOnePastTheEnd, CallIndex, IsNullPtr); + Designator.IsOnePastTheEnd, IsNullPtr); } } void setFrom(ASTContext &Ctx, const APValue &V) { @@ -1282,12 +1335,11 @@ Base = V.getLValueBase(); Offset = V.getLValueOffset(); InvalidBase = false; - CallIndex = V.getLValueCallIndex(); Designator = SubobjectDesignator(Ctx, V); IsNullPtr = V.isNullPointer(); } - void set(APValue::LValueBase B, unsigned I = 0, bool BInvalid = false) { + void set(APValue::LValueBase B, bool BInvalid = false) { #ifndef NDEBUG // We only allow a few types of invalid bases. Enforce that here. if (BInvalid) { @@ -1300,7 +1352,6 @@ Base = B; Offset = CharUnits::fromQuantity(0); InvalidBase = BInvalid; - CallIndex = I; Designator = SubobjectDesignator(getType(B)); IsNullPtr = false; } @@ -1309,13 +1360,12 @@ Base = (Expr *)nullptr; Offset = CharUnits::fromQuantity(TargetVal); InvalidBase = false; - CallIndex = 0; Designator = SubobjectDesignator(PointerTy->getPointeeType()); IsNullPtr = true; } void setInvalid(APValue::LValueBase B, unsigned I = 0) { - set(B, I, true); + set(B, true); } // Check that this LValue is not based on a null pointer. If it is, produce @@ -1517,6 +1567,15 @@ // Misc utilities //===----------------------------------------------------------------------===// +/// A helper function to create a temporary and set an LValue. +template +static APValue &createTemporary(const KeyTy *Key, bool IsLifetimeExtended, + LValue &LV, CallStackFrame &Frame) { + LV.set({Key, Frame.Info.CurrentCall->Index, + Frame.Info.CurrentCall->getTempVersion()}); + return Frame.createTemporary(Key, IsLifetimeExtended); +} + /// Negate an APSInt in place, converting it to a signed form if necessary, and /// preserving its value (by extending by up to one bit as needed). static void negateAsSigned(APSInt &Int) { @@ -1846,7 +1905,7 @@ } static bool IsLiteralLValue(const LValue &Value) { - if (Value.CallIndex) + if (Value.getLValueCallIndex()) return false; const Expr *E = Value.Base.dyn_cast(); return E && !isa(E); @@ -2396,7 +2455,7 @@ /// \param Result Filled in with a pointer to the value of the variable. static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E, const VarDecl *VD, CallStackFrame *Frame, - APValue *&Result) { + APValue *&Result, const LValue *LVal) { // If this is a parameter to an active constexpr function call, perform // argument substitution. @@ -2415,7 +2474,8 @@ // If this is a local variable, dig out its value. if (Frame) { - Result = Frame->getTemporary(VD); + Result = LVal ? Frame->getTemporary(VD, LVal->getLValueVersion()) + : Frame->getCurrentTemporary(VD); if (!Result) { // Assume variables referenced within a lambda's call operator that were // not declared within the call operator are captures and during checking @@ -2992,8 +3052,8 @@ } CallStackFrame *Frame = nullptr; - if (LVal.CallIndex) { - Frame = Info.getCallFrame(LVal.CallIndex); + if (LVal.getLValueCallIndex()) { + Frame = Info.getCallFrame(LVal.getLValueCallIndex()); if (!Frame) { Info.FFDiag(E, diag::note_constexpr_lifetime_ended, 1) << AK << LVal.Base.is(); @@ -3105,7 +3165,7 @@ } } - if (!evaluateVarDeclInit(Info, E, VD, Frame, BaseVal)) + if (!evaluateVarDeclInit(Info, E, VD, Frame, BaseVal, &LVal)) return CompleteObject(); } else { const Expr *Base = LVal.Base.dyn_cast(); @@ -3147,7 +3207,7 @@ return CompleteObject(); } } else { - BaseVal = Frame->getTemporary(Base); + BaseVal = Frame->getTemporary(Base, LVal.Base.getVersion()); assert(BaseVal && "missing value for temporary"); } @@ -3167,7 +3227,9 @@ // During the construction of an object, it is not yet 'const'. // FIXME: This doesn't do quite the right thing for const subobjects of the // object under construction. - if (Info.isEvaluatingConstructor(LVal.getLValueBase(), LVal.CallIndex)) { + if (Info.isEvaluatingConstructor(LVal.getLValueBase(), + LVal.getLValueCallIndex(), + LVal.getLValueVersion())) { BaseType = Info.Ctx.getCanonicalType(BaseType); BaseType.removeLocalConst(); } @@ -3204,7 +3266,7 @@ // Check for special cases where there is no existing APValue to look at. const Expr *Base = LVal.Base.dyn_cast(); - if (Base && !LVal.CallIndex && !Type.isVolatileQualified()) { + if (Base && !LVal.getLValueCallIndex() && !Type.isVolatileQualified()) { if (const CompoundLiteralExpr *CLE = dyn_cast(Base)) { // In C99, a CompoundLiteralExpr is an lvalue, and we defer evaluating the // initializer until now for such expressions. Such an expression can't be @@ -3700,8 +3762,7 @@ return true; LValue Result; - Result.set(VD, Info.CurrentCall->Index); - APValue &Val = Info.CurrentCall->createTemporary(VD, true); + APValue &Val = createTemporary(VD, true, Result, *Info.CurrentCall); const Expr *InitE = VD->getInit(); if (!InitE) { @@ -3757,6 +3818,19 @@ /// The location containing the result, if any (used to support RVO). const LValue *Slot; }; + +struct TempVersionRAII { + CallStackFrame &Frame; + + TempVersionRAII(CallStackFrame &Frame) : Frame(Frame) { + Frame.pushTempVersion(); + } + + ~TempVersionRAII() { + Frame.popTempVersion(); + } +}; + } static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info, @@ -4314,7 +4388,8 @@ } EvalInfo::EvaluatingConstructorRAII EvalObj( - Info, {This.getLValueBase(), This.CallIndex}); + Info, {This.getLValueBase(), + {This.getLValueCallIndex(), This.getLValueVersion()}}); CallStackFrame Frame(Info, CallLoc, Definition, &This, ArgValues); // FIXME: Creating an APValue just to hold a nonexistent return value is @@ -4563,9 +4638,12 @@ { return StmtVisitorTy::Visit(E->getResultExpr()); } bool VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E) { return StmtVisitorTy::Visit(E->getReplacement()); } - bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E) - { return StmtVisitorTy::Visit(E->getExpr()); } + bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E) { + TempVersionRAII RAII(*Info.CurrentCall); + return StmtVisitorTy::Visit(E->getExpr()); + } bool VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E) { + TempVersionRAII RAII(*Info.CurrentCall); // The initializer may not have been parsed yet, or might be erroneous. if (!E->getExpr()) return Error(E); @@ -4643,7 +4721,7 @@ } bool VisitOpaqueValueExpr(const OpaqueValueExpr *E) { - if (APValue *Value = Info.CurrentCall->getTemporary(E)) + if (APValue *Value = Info.CurrentCall->getCurrentTemporary(E)) return DerivedSuccess(*Value, E); const Expr *Source = E->getSourceExpr(); @@ -5201,14 +5279,15 @@ if (!VD->getType()->isReferenceType()) { if (Frame) { - Result.set(VD, Frame->Index); + Result.set({VD, Frame->Index, + Info.CurrentCall->getCurrentTemporaryVersion(VD)}); return true; } return Success(VD); } APValue *V; - if (!evaluateVarDeclInit(Info, E, VD, Frame, V)) + if (!evaluateVarDeclInit(Info, E, VD, Frame, V, nullptr)) return false; if (V->isUninit()) { if (!Info.checkingPotentialConstantExpression()) @@ -5240,9 +5319,8 @@ *Value = APValue(); Result.set(E); } else { - Value = &Info.CurrentCall-> - createTemporary(E, E->getStorageDuration() == SD_Automatic); - Result.set(E, Info.CurrentCall->Index); + Value = &createTemporary(E, E->getStorageDuration() == SD_Automatic, Result, + *Info.CurrentCall); } QualType Type = Inner->getType(); @@ -5721,7 +5799,6 @@ Result.Base = (Expr*)nullptr; Result.InvalidBase = false; Result.Offset = CharUnits::fromQuantity(N); - Result.CallIndex = 0; Result.Designator.setInvalid(); Result.IsNullPtr = false; return true; @@ -5737,9 +5814,9 @@ if (!evaluateLValue(SubExpr, Result)) return false; } else { - Result.set(SubExpr, Info.CurrentCall->Index); - if (!EvaluateInPlace(Info.CurrentCall->createTemporary(SubExpr, false), - Info, Result, SubExpr)) + APValue &Value = createTemporary(SubExpr, false, Result, + *Info.CurrentCall); + if (!EvaluateInPlace(Value, Info, Result, SubExpr)) return false; } // The result is a pointer to the first element of the array. @@ -6505,9 +6582,8 @@ /// Visit an expression which constructs the value of this temporary. bool VisitConstructExpr(const Expr *E) { - Result.set(E, Info.CurrentCall->Index); - return EvaluateInPlace(Info.CurrentCall->createTemporary(E, false), - Info, Result, E); + APValue &Value = createTemporary(E, false, Result, *Info.CurrentCall); + return EvaluateInPlace(Value, Info, Result, E); } bool VisitCastExpr(const CastExpr *E) { @@ -7992,7 +8068,8 @@ } return IsGlobalLValue(A.getLValueBase()) || - A.getLValueCallIndex() == B.getLValueCallIndex(); + (A.getLValueCallIndex() == B.getLValueCallIndex() && + A.getLValueVersion() == B.getLValueVersion()); } /// \brief Determine whether this is a pointer past the end of the complete @@ -9935,15 +10012,13 @@ return true; } else if (T->isArrayType()) { LValue LV; - LV.set(E, Info.CurrentCall->Index); - APValue &Value = Info.CurrentCall->createTemporary(E, false); + APValue &Value = createTemporary(E, false, LV, *Info.CurrentCall); if (!EvaluateArray(E, LV, Value, Info)) return false; Result = Value; } else if (T->isRecordType()) { LValue LV; - LV.set(E, Info.CurrentCall->Index); - APValue &Value = Info.CurrentCall->createTemporary(E, false); + APValue &Value = createTemporary(E, false, LV, *Info.CurrentCall); if (!EvaluateRecord(E, LV, Value, Info)) return false; Result = Value; @@ -9957,8 +10032,7 @@ QualType Unqual = T.getAtomicUnqualifiedType(); if (Unqual->isArrayType() || Unqual->isRecordType()) { LValue LV; - LV.set(E, Info.CurrentCall->Index); - APValue &Value = Info.CurrentCall->createTemporary(E, false); + APValue &Value = createTemporary(E, false, LV, *Info.CurrentCall); if (!EvaluateAtomic(E, &LV, Value, Info)) return false; } else { @@ -10780,7 +10854,7 @@ // is a temporary being used as the 'this' pointer. LValue This; ImplicitValueInitExpr VIE(RD ? Info.Ctx.getRecordType(RD) : Info.Ctx.IntTy); - This.set(&VIE, Info.CurrentCall->Index); + This.set({&VIE, Info.CurrentCall->Index}); ArrayRef Args; Index: test/SemaCXX/constant-expression-cxx1y.cpp =================================================================== --- test/SemaCXX/constant-expression-cxx1y.cpp +++ test/SemaCXX/constant-expression-cxx1y.cpp @@ -852,7 +852,6 @@ static_assert(h(2) == 0, ""); // expected-error {{constant expression}} expected-note {{in call}} static_assert(h(3) == 0, ""); // expected-error {{constant expression}} expected-note {{in call}} - // FIXME: This function should be treated as non-constant. constexpr void lifetime_versus_loops() { int *p = 0; for (int i = 0; i != 2; ++i) { @@ -862,10 +861,10 @@ if (i) // This modifies the 'n' from the previous iteration of the loop outside // its lifetime. - ++*q; + ++*q; // expected-note {{increment of object outside its lifetime}} } } - static_assert((lifetime_versus_loops(), true), ""); + static_assert((lifetime_versus_loops(), true), ""); // expected-error {{constant expression}} expected-note {{in call}} } namespace Bitfields { Index: test/SemaCXX/constexpr-default-arg.cpp =================================================================== --- /dev/null +++ test/SemaCXX/constexpr-default-arg.cpp @@ -0,0 +1,38 @@ +// RUN: %clang_cc1 -std=c++1y -S -o - -emit-llvm -verify %s + +namespace default_arg_temporary { + +constexpr bool equals(const float& arg = 1.0f) { + return arg == 1.0f; +} + +constexpr const int &x(const int &p = 0) { + return p; +} + +struct S { + constexpr S(const int &a = 0) {} +}; + +void test_default_arg2() { + // This piece of code used to cause an assertion failure in + // CallStackFrame::createTemporary because the same MTE is used to initilize + // both elements of the array (see PR33140). + constexpr S s[2] = {}; + + // This piece of code used to cause an assertion failure in + // CallStackFrame::createTemporary because multiple CXXDefaultArgExpr share + // the same MTE (see PR33140). + static_assert(equals() && equals(), ""); + + // Test that constant expression evaluation produces distinct lvalues for + // each call. + static_assert(&x() != &x(), ""); +} + +// Check that multiple CXXDefaultInitExprs don't cause an assertion failure. +struct A { int &&r = 0; }; // expected-warning {{binding reference member}} // expected-note {{reference member declared here}} +struct B { A x, y; }; +B b = {}; + +}