ahatanak updated this revision to Diff 133947.
ahatanak marked 2 inline comments as done.
ahatanak added a comment.

Address Erik's and Roman's review comments.


https://reviews.llvm.org/D42776

Files:
  include/clang/AST/APValue.h
  lib/AST/APValue.cpp
  lib/AST/ExprConstant.cpp
  test/SemaCXX/constexpr-default-arg.cpp

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(), "");
+}
+
+}
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<const void*, APValue> MapTy;
+    typedef std::pair<const void*, unsigned> KeyTy;
+    typedef std::map<KeyTy, APValue> 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<Cleanup, 16> 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: lib/AST/APValue.cpp
===================================================================
--- lib/AST/APValue.cpp
+++ lib/AST/APValue.cpp
@@ -23,14 +23,54 @@
 
 namespace {
   struct LVBase {
-    llvm::PointerIntPair<APValue::LValueBase, 1, bool> BaseAndIsOnePastTheEnd;
+    APValue::LValueBase Base;
+    bool IsOnePastTheEnd;
     CharUnits Offset;
     unsigned PathLength;
     unsigned CallIndex;
     bool IsNullPtr;
   };
 }
 
+void *APValue::LValueBase::getOpaqueValue() const {
+  return Ptr.getOpaqueValue();
+}
+
+bool APValue::LValueBase::isNull() const {
+  return Ptr.isNull();
+}
+
+APValue::LValueBase::operator bool () const {
+  return static_cast<bool>(Ptr);
+}
+
+clang::APValue::LValueBase
+llvm::DenseMapInfo<clang::APValue::LValueBase>::getEmptyKey() {
+  return clang::APValue::LValueBase(
+      DenseMapInfo<clang::APValue::LValueBase::PtrTy>::getEmptyKey(),
+      DenseMapInfo<unsigned>::getEmptyKey());
+}
+
+clang::APValue::LValueBase
+llvm::DenseMapInfo<clang::APValue::LValueBase>::getTombstoneKey() {
+  return clang::APValue::LValueBase(
+      DenseMapInfo<clang::APValue::LValueBase::PtrTy>::getTombstoneKey(),
+      DenseMapInfo<unsigned>::getTombstoneKey());
+}
+
+unsigned llvm::DenseMapInfo<clang::APValue::LValueBase>::getHashValue(
+    const clang::APValue::LValueBase &Base) {
+  using PairTy = std::pair<clang::APValue::LValueBase::PtrTy, unsigned>;
+  return DenseMapInfo<PairTy>::getHashValue(
+      PairTy(Base.getPointer(), Base.getVersion()));
+}
+
+bool llvm::DenseMapInfo<clang::APValue::LValueBase>::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: include/clang/AST/APValue.h
===================================================================
--- include/clang/AST/APValue.h
+++ include/clang/AST/APValue.h
@@ -53,7 +53,48 @@
     MemberPointer,
     AddrLabelDiff
   };
-  typedef llvm::PointerUnion<const ValueDecl *, const Expr *> LValueBase;
+
+  class LValueBase {
+  public:
+    typedef llvm::PointerUnion<const ValueDecl *, const Expr *> PtrTy;
+
+    LValueBase() : Version(0) {}
+
+    template <class T>
+    LValueBase(T P, unsigned V = 0) : Ptr(P), Version(V) {}
+
+    template <class T>
+    bool is() const { return Ptr.is<T>(); }
+
+    template <class T>
+    T get() const { return Ptr.get<T>(); }
+
+    template <class T>
+    T dyn_cast() const { return Ptr.dyn_cast<T>(); }
+
+    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<const Decl *, 1, bool> BaseOrMemberType;
   union LValuePathEntry {
     /// BaseOrMember - The FieldDecl or CXXRecordDecl indicating the next item
@@ -451,4 +492,14 @@
 
 } // end namespace clang.
 
+namespace llvm {
+template<> struct DenseMapInfo<clang::APValue::LValueBase> {
+  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
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to