Index: include/clang/AST/APValue.h =================================================================== --- include/clang/AST/APValue.h +++ include/clang/AST/APValue.h @@ -53,7 +53,48 @@ MemberPointer, AddrLabelDiff }; - typedef llvm::PointerUnion LValueBase; + + class LValueBase { + public: + typedef llvm::PointerUnion PtrTy; + + LValueBase() : Version(0) {} + + template + LValueBase(T P, unsigned V = 0) : Ptr(P), 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 getVersion() const { + return Version; + } + + bool operator==(const LValueBase &Other) const { + return Ptr == Other.Ptr && Version == Other.Version; + } + + private: + PtrTy Ptr; + unsigned Version; + }; + typedef llvm::PointerIntPair BaseOrMemberType; union LValuePathEntry { /// BaseOrMember - The FieldDecl or CXXRecordDecl indicating the next item @@ -451,4 +492,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,7 +23,8 @@ namespace { struct LVBase { - llvm::PointerIntPair BaseAndIsOnePastTheEnd; + APValue::LValueBase Base; + bool IsOnePastTheEnd; CharUnits Offset; unsigned PathLength; unsigned CallIndex; @@ -31,6 +32,45 @@ }; } +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()); +} + +clang::APValue::LValueBase +llvm::DenseMapInfo::getTombstoneKey() { + return clang::APValue::LValueBase( + DenseMapInfo::getTombstoneKey(), + DenseMapInfo::getTombstoneKey()); +} + +unsigned llvm::DenseMapInfo::getHashValue( + const clang::APValue::LValueBase &Base) { + using PairTy = std::pair; + return DenseMapInfo::getHashValue( + PairTy(Base.getPointer(), Base.getVersion())); +} + +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); @@ -552,12 +592,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() { @@ -590,8 +630,8 @@ unsigned CallIndex, 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); @@ -603,8 +643,8 @@ unsigned CallIndex, 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()); 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; @@ -465,11 +466,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'. @@ -584,6 +586,17 @@ /// initialized after CurrentCall and CallStackDepth. CallStackFrame BottomFrame; + /// Keep track of the version of MTEs that are used by CXXDefaultArgExpr. + /// The version number is updated every time VisitCXXDefaultArgExpr is + /// called. + unsigned getDefaultArgNum() const { return CurDefaultArgNum; } + void setDefaultArgNum() { + assert(CurDefaultArgNum == 0 && "CurDefaultArgNum hasn't been cleared"); + CurDefaultArgNum = ++NextDefaultArgNum; + } + void clearDefaultArgNum() { CurDefaultArgNum = 0; } + unsigned CurDefaultArgNum = 0, NextDefaultArgNum = 0; + /// A stack of values whose lifetimes end at the end of some surrounding /// evaluation frame. llvm::SmallVector CleanupStack; @@ -1161,8 +1174,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; @@ -3147,7 +3161,7 @@ return CompleteObject(); } } else { - BaseVal = Frame->getTemporary(Base); + BaseVal = Frame->getTemporary(Base, LVal.Base.getVersion()); assert(BaseVal && "missing value for temporary"); } @@ -4529,6 +4543,17 @@ bool ZeroInitialization(const Expr *E) { return Error(E); } + struct DefaultArgRAII { + EvalInfo &Info; + + DefaultArgRAII(EvalInfo &Info) : Info(Info) { + Info.setDefaultArgNum(); + } + ~DefaultArgRAII() { + Info.clearDefaultArgNum(); + } + }; + public: ExprEvaluatorBase(EvalInfo &Info) : Info(Info) {} @@ -4563,8 +4588,10 @@ { 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); + return StmtVisitorTy::Visit(E->getExpr()); + } bool VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E) { // The initializer may not have been parsed yet, or might be erroneous. if (!E->getExpr()) @@ -5240,9 +5267,10 @@ *Value = APValue(); Result.set(E); } else { + unsigned Version = Info.getDefaultArgNum(); Value = &Info.CurrentCall-> - createTemporary(E, E->getStorageDuration() == SD_Automatic); - Result.set(E, Info.CurrentCall->Index); + createTemporary(E, E->getStorageDuration() == SD_Automatic, Version); + Result.set(APValue::LValueBase(E, Version), Info.CurrentCall->Index); } QualType Type = Inner->getType(); @@ -7981,6 +8009,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); Index: test/SemaCXX/constexpr-default-arg.cpp =================================================================== --- /dev/null +++ test/SemaCXX/constexpr-default-arg.cpp @@ -0,0 +1,35 @@ +// RUN: %clang_cc1 -std=c++1y -fsyntax-only -verify %s + +// expected-no-diagnostics + +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(), ""); +} + +}