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,7 +438,8 @@ // Note that we intentionally use std::map here so that references to // values are stable. - typedef std::map MapTy; + typedef std::pair KeyTy; + typedef std::map MapTy; typedef MapTy::const_iterator temp_iterator; /// Temporaries - Temporary lvalues materialized within this stack frame. MapTy Temporaries; @@ -449,6 +450,22 @@ /// Index - The call index of this call. unsigned Index; + /// Keep track of the version of MTEs that are used by CXXDefaultArgExpr or + /// CXXDefaultInitExpr. The version number is updated every time + /// VisitCXXDefaultArgExpr or VisitCXXDefaultInitExpr is visited. + unsigned NextMTEVersion = 0; + SmallVector MTEVersionStack = {0}; + + unsigned getMTEVersion() const { return MTEVersionStack.back(); } + + void pushMTEVersion() { + MTEVersionStack.push_back(++NextMTEVersion); + } + + void popMTEVersion() { + MTEVersionStack.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,11 +482,12 @@ APValue *Arguments); ~CallStackFrame(); - APValue *getTemporary(const void *Key) { - MapTy::iterator I = Temporaries.find(Key); + APValue *getTemporary(const void *Key, unsigned Version = 0) { + MapTy::iterator I = Temporaries.find(KeyTy(Key, Version)); return I == Temporaries.end() ? nullptr : &I->second; } - APValue &createTemporary(const void *Key, bool IsLifetimeExtended); + APValue &createTemporary(const void *Key, bool IsLifetimeExtended, + unsigned Version = 0); }; /// Temporarily override 'this'. @@ -1161,8 +1179,9 @@ } APValue &CallStackFrame::createTemporary(const void *Key, - bool IsLifetimeExtended) { - APValue &Result = Temporaries[Key]; + bool IsLifetimeExtended, + unsigned Version) { + APValue &Result = Temporaries[KeyTy(Key, Version)]; assert(Result.isUninit() && "temporary created multiple times"); Info.CleanupStack.push_back(Cleanup(&Result, IsLifetimeExtended)); return Result; @@ -1254,27 +1273,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 +1301,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 +1318,6 @@ Base = B; Offset = CharUnits::fromQuantity(0); InvalidBase = BInvalid; - CallIndex = I; Designator = SubobjectDesignator(getType(B)); IsNullPtr = false; } @@ -1309,13 +1326,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 @@ -1846,7 +1862,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); @@ -2992,8 +3008,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(); @@ -3147,7 +3163,7 @@ return CompleteObject(); } } else { - BaseVal = Frame->getTemporary(Base); + BaseVal = Frame->getTemporary(Base, LVal.Base.getVersion()); assert(BaseVal && "missing value for temporary"); } @@ -3167,7 +3183,8 @@ // 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())) { BaseType = Info.Ctx.getCanonicalType(BaseType); BaseType.removeLocalConst(); } @@ -3204,7 +3221,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,7 +3717,7 @@ return true; LValue Result; - Result.set(VD, Info.CurrentCall->Index); + Result.set({VD, Info.CurrentCall->Index}); APValue &Val = Info.CurrentCall->createTemporary(VD, true); const Expr *InitE = VD->getInit(); @@ -4314,7 +4331,7 @@ } EvalInfo::EvaluatingConstructorRAII EvalObj( - Info, {This.getLValueBase(), This.CallIndex}); + Info, {This.getLValueBase(), This.getLValueCallIndex()}); CallStackFrame Frame(Info, CallLoc, Definition, &This, ArgValues); // FIXME: Creating an APValue just to hold a nonexistent return value is @@ -4529,6 +4546,18 @@ bool ZeroInitialization(const Expr *E) { return Error(E); } + struct DefaultArgRAII { + CallStackFrame &Frame; + + DefaultArgRAII(CallStackFrame &Frame) : Frame(Frame) { + Frame.pushMTEVersion(); + } + + ~DefaultArgRAII() { + Frame.popMTEVersion(); + } + }; + public: ExprEvaluatorBase(EvalInfo &Info) : Info(Info) {} @@ -4563,9 +4592,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) { + DefaultArgRAII RAII(*Info.CurrentCall); + return StmtVisitorTy::Visit(E->getExpr()); + } bool VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E) { + DefaultArgRAII RAII(*Info.CurrentCall); // The initializer may not have been parsed yet, or might be erroneous. if (!E->getExpr()) return Error(E); @@ -5201,7 +5233,7 @@ if (!VD->getType()->isReferenceType()) { if (Frame) { - Result.set(VD, Frame->Index); + Result.set({VD, Frame->Index}); return true; } return Success(VD); @@ -5240,9 +5272,10 @@ *Value = APValue(); Result.set(E); } else { + unsigned Version = Info.CurrentCall->getMTEVersion(); Value = &Info.CurrentCall-> - createTemporary(E, E->getStorageDuration() == SD_Automatic); - Result.set(E, Info.CurrentCall->Index); + createTemporary(E, E->getStorageDuration() == SD_Automatic, Version); + Result.set({E, Info.CurrentCall->Index, Version}); } QualType Type = Inner->getType(); @@ -5721,7 +5754,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,7 +5769,7 @@ if (!evaluateLValue(SubExpr, Result)) return false; } else { - Result.set(SubExpr, Info.CurrentCall->Index); + Result.set({SubExpr, Info.CurrentCall->Index}); if (!EvaluateInPlace(Info.CurrentCall->createTemporary(SubExpr, false), Info, Result, SubExpr)) return false; @@ -6505,7 +6537,7 @@ /// Visit an expression which constructs the value of this temporary. bool VisitConstructExpr(const Expr *E) { - Result.set(E, Info.CurrentCall->Index); + Result.set({E, Info.CurrentCall->Index}); return EvaluateInPlace(Info.CurrentCall->createTemporary(E, false), Info, Result, E); } @@ -7981,6 +8013,9 @@ if (!B.getLValueBase()) return false; + if (A.getLValueBase().getVersion() != B.getLValueBase().getVersion()) + return false; + if (A.getLValueBase().getOpaqueValue() != B.getLValueBase().getOpaqueValue()) { const Decl *ADecl = GetLValueBaseDecl(A); @@ -7992,7 +8027,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,14 +9971,14 @@ return true; } else if (T->isArrayType()) { LValue LV; - LV.set(E, Info.CurrentCall->Index); + LV.set({E, Info.CurrentCall->Index}); APValue &Value = Info.CurrentCall->createTemporary(E, false); if (!EvaluateArray(E, LV, Value, Info)) return false; Result = Value; } else if (T->isRecordType()) { LValue LV; - LV.set(E, Info.CurrentCall->Index); + LV.set({E, Info.CurrentCall->Index}); APValue &Value = Info.CurrentCall->createTemporary(E, false); if (!EvaluateRecord(E, LV, Value, Info)) return false; @@ -9957,7 +9993,7 @@ QualType Unqual = T.getAtomicUnqualifiedType(); if (Unqual->isArrayType() || Unqual->isRecordType()) { LValue LV; - LV.set(E, Info.CurrentCall->Index); + LV.set({E, Info.CurrentCall->Index}); APValue &Value = Info.CurrentCall->createTemporary(E, false); if (!EvaluateAtomic(E, &LV, Value, Info)) return false; @@ -10780,7 +10816,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/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 = {}; + +}