Index: include/llvm/ADT/STLExtras.h =================================================================== --- include/llvm/ADT/STLExtras.h +++ include/llvm/ADT/STLExtras.h @@ -536,6 +536,63 @@ } }; +class Switch { + bool TurnedOn; +public: + Switch() : TurnedOn(true) {} + void TurnOn() { TurnedOn = true; } + void TurnOff() { TurnedOn = false; } + bool IsTurnedOn() const { return TurnedOn; } +}; + +template +class SwitchControlledDeleter : public Switch { +public: + void operator()(T* p) { + if (IsTurnedOn()) + delete(p); + } +}; + +/// \brief unique_ptr that allows accessing a raw pointer after release. +/// +/// Intended for use in cases when conditional releases are mixed with raw +/// pointer access. +/// +/// Example: +/// +/// unique_ptr_deferred_release P(new P); +/// if (cond) { +/// P.release(); +/// } +/// assert(P.get()); // 'true' regardless of whether release() was called +/// // or not. +/// NonOwningFunction(P.get()); +template> +class unique_ptr_deferred_release : public std::unique_ptr { +public: + typedef typename std::unique_ptr Base; + + unique_ptr_deferred_release() {} + explicit unique_ptr_deferred_release(T* p) : Base(p) {}; + + typename Base::pointer release() { + Base::get_deleter().TurnOff(); + return Base::get(); + } + + void reset(pointer p = pointer()) { + if (p != Base::get()) { + Base::reset(p); + Base::get_deleter().TurnOn(); + } + } + + bool released() const { + return !Base::get_deleter().IsTurnedOn(); + } +}; + template struct pair_hash { size_t operator()(const std::pair &P) const { Index: lib/TableGen/TGParser.cpp =================================================================== --- lib/TableGen/TGParser.cpp +++ lib/TableGen/TGParser.cpp @@ -232,16 +232,14 @@ i != iend; ++i) { // Clone the def and add it to the current multiclass - Record *NewDef = new Record(**i); + auto NewDef = make_unique(**i); // Add all of the values in the superclass into the current def. for (unsigned i = 0, e = MCVals.size(); i != e; ++i) - if (AddValue(NewDef, SubMultiClass.RefRange.Start, MCVals[i])) { - delete NewDef; + if (AddValue(NewDef.get(), SubMultiClass.RefRange.Start, MCVals[i])) return true; - } - CurMC->DefPrototypes.push_back(NewDef); + CurMC->DefPrototypes.push_back(NewDef.release()); } const std::vector &SMCTArgs = SMC->Rec.getTemplateArgs(); @@ -342,7 +340,7 @@ // This is the bottom of the recursion. We have all of the iterator values // for this point in the iteration space. Instantiate a new record to // reflect this combination of values. - Record *IterRec = new Record(*CurRec); + unique_ptr_deferred_release IterRec(new Record(*CurRec)); // Set the iterator values now. for (unsigned i = 0, e = IterVals.size(); i != e; ++i) { @@ -350,16 +348,14 @@ TypedInit *IVal = dyn_cast(IterVals[i].IterValue); if (!IVal) { Error(Loc, "foreach iterator value is untyped"); - delete IterRec; return true; } IterRec->addValue(RecordVal(IterVar->getName(), IVal->getType(), false)); - if (SetValue(IterRec, Loc, IterVar->getName(), + if (SetValue(IterRec.get(), Loc, IterVar->getName(), std::vector(), IVal)) { Error(Loc, "when instantiating this def"); - delete IterRec; return true; } @@ -376,12 +372,11 @@ IterRec->setName(GetNewAnonymousName()); else { Error(Loc, "def already exists: " + IterRec->getNameInitAsString()); - delete IterRec; return true; } } - Records.addDef(IterRec); + Records.addDef(IterRec.release()); IterRec->resolveReferences(); return false; } @@ -1249,26 +1244,25 @@ SMLoc EndLoc = Lex.getLoc(); // Create the new record, set it as CurRec temporarily. - Record *NewRec = new Record(GetNewAnonymousName(), NameLoc, Records, - /*IsAnonymous=*/true); + unique_ptr_deferred_release + NewRec(new Record(GetNewAnonymousName(), NameLoc, Records, + /*IsAnonymous=*/true)); SubClassReference SCRef; SCRef.RefRange = SMRange(NameLoc, EndLoc); SCRef.Rec = Class; SCRef.TemplateArgs = ValueList; // Add info about the subclass to NewRec. - if (AddSubClass(NewRec, SCRef)) { - delete NewRec; + if (AddSubClass(NewRec.get(), SCRef)) return nullptr; - } if (!CurMultiClass) { NewRec->resolveReferences(); - Records.addDef(NewRec); + Records.addDef(NewRec.release()); } else { // This needs to get resolved once the multiclass template arguments are // known before any use. NewRec->setResolveFirst(true); // Otherwise, we're inside a multiclass, add it to the multiclass. - CurMultiClass->DefPrototypes.push_back(NewRec); + CurMultiClass->DefPrototypes.push_back(NewRec.release()); // Copy the template arguments for the multiclass into the def. const std::vector &TArgs = @@ -1295,7 +1289,7 @@ } // The result of the expression is a reference to the new record. - return DefInit::get(NewRec); + return DefInit::get(NewRec.get()); } case tgtok::l_brace: { // Value ::= '{' ValueList '}' SMLoc BraceLoc = Lex.getLoc(); @@ -2038,14 +2032,14 @@ Lex.Lex(); // Eat the 'def' token. // Parse ObjectName and make a record for it. - Record *CurRec; - bool CurRecOwnershipTransferred = false; + unique_ptr_deferred_release CurRec; + Init *Name = ParseObjectName(CurMultiClass); if (Name) - CurRec = new Record(Name, DefLoc, Records); + CurRec.reset(new Record(Name, DefLoc, Records)); else - CurRec = new Record(GetNewAnonymousName(), DefLoc, Records, - /*IsAnonymous=*/true); + CurRec.reset(new Record(GetNewAnonymousName(), DefLoc, Records, + /*IsAnonymous=*/true)); if (!CurMultiClass && Loops.empty()) { // Top-level def definition. @@ -2054,13 +2048,12 @@ if (Records.getDef(CurRec->getNameInitAsString())) { Error(DefLoc, "def '" + CurRec->getNameInitAsString() + "' already defined"); - delete CurRec; return true; } - Records.addDef(CurRec); - CurRecOwnershipTransferred = true; - if (ParseObjectBody(CurRec)) + Records.addDef(CurRec.release()); + + if (ParseObjectBody(CurRec.get())) return true; } else if (CurMultiClass) { // Parse the body before adding this prototype to the DefPrototypes vector. @@ -2068,10 +2061,8 @@ // before this object, instantiated prior to defs derived from this object, // and this available for indirect name resolution when defs derived from // this object are instantiated. - if (ParseObjectBody(CurRec)) { - delete CurRec; + if (ParseObjectBody(CurRec.get())) return true; - } // Otherwise, a def inside a multiclass, add it to the multiclass. for (unsigned i = 0, e = CurMultiClass->DefPrototypes.size(); i != e; ++i) @@ -2079,13 +2070,10 @@ == CurRec->getNameInit()) { Error(DefLoc, "def '" + CurRec->getNameInitAsString() + "' already defined in this multiclass!"); - delete CurRec; return true; } - CurMultiClass->DefPrototypes.push_back(CurRec); - CurRecOwnershipTransferred = true; - } else if (ParseObjectBody(CurRec)) { - delete CurRec; + CurMultiClass->DefPrototypes.push_back(CurRec.release()); + } else if (ParseObjectBody(CurRec.get())) { return true; } @@ -2110,16 +2098,12 @@ } } - if (ProcessForeachDefs(CurRec, DefLoc)) { + if (ProcessForeachDefs(CurRec.get(), DefLoc)) { Error(DefLoc, "Could not process loops for def" + CurRec->getNameInitAsString()); - if (!CurRecOwnershipTransferred) - delete CurRec; return true; } - if (!CurRecOwnershipTransferred) - delete CurRec; return false; } @@ -2418,22 +2402,22 @@ // Make a trail of SMLocs from the multiclass instantiations. SmallVector Locs(1, DefmPrefixRange.Start); Locs.append(DefProto->getLoc().begin(), DefProto->getLoc().end()); - Record *CurRec = new Record(DefName, Locs, Records, IsAnonymous); + unique_ptr_deferred_release + CurRec(new Record(DefName, Locs, Records, IsAnonymous)); SubClassReference Ref; Ref.RefRange = DefmPrefixRange; Ref.Rec = DefProto; - AddSubClass(CurRec, Ref); + AddSubClass(CurRec.get(), Ref); // Set the value for NAME. We don't resolve references to it 'til later, // though, so that uses in nested multiclass names don't get // confused. - if (SetValue(CurRec, Ref.RefRange.Start, "NAME", std::vector(), - DefmPrefix)) { + if (SetValue(CurRec.get(), Ref.RefRange.Start, "NAME", + std::vector(), DefmPrefix)) { Error(DefmPrefixRange.Start, "Could not resolve " + CurRec->getNameInitAsString() + ":NAME to '" + DefmPrefix->getAsUnquotedString() + "'"); - delete CurRec; return nullptr; } @@ -2465,14 +2449,13 @@ Error(DefmPrefixRange.Start, "def '" + CurRec->getNameInitAsString() + "' already defined, instantiating defm with subdef '" + DefProto->getNameInitAsString() + "'"); - delete CurRec; return nullptr; } - Records.addDef(CurRec); + Records.addDef(CurRec.release()); } - return CurRec; + return CurRec.release(); } bool TGParser::ResolveMulticlassDefArgs(MultiClass &MC, Index: unittests/ADT/CMakeLists.txt =================================================================== --- unittests/ADT/CMakeLists.txt +++ unittests/ADT/CMakeLists.txt @@ -38,6 +38,7 @@ TinyPtrVectorTest.cpp TripleTest.cpp TwineTest.cpp + UniquePtrDeferredReleaseTest.cpp VariadicFunctionTest.cpp ) Index: unittests/ADT/UniquePtrDeferredReleaseTest.cpp =================================================================== --- unittests/ADT/UniquePtrDeferredReleaseTest.cpp +++ unittests/ADT/UniquePtrDeferredReleaseTest.cpp @@ -0,0 +1,62 @@ +//===- UniquePtrDeferredReleaseTest.cpp -----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "gtest/gtest.h" +#include "llvm/ADT/STLExtras.h" + +using namespace llvm; + +namespace { + +TEST(UniquePtrDeferredRelease, Release) { + unique_ptr_deferred_release P(new int); + EXPECT_TRUE(P); + + P.release(); + EXPECT_TRUE(P); + EXPECT_TRUE(P.released()); + EXPECT_TRUE(P.get()); + + delete P.get(); +} + +TEST(UniquePtrDeferredRelease, Reset) { + unique_ptr_deferred_release P(new int); + + P.reset(); + EXPECT_FALSE(P); + EXPECT_FALSE(P.released()); + EXPECT_FALSE(P.get()); + + P.release(); + EXPECT_FALSE(P); + EXPECT_TRUE(P.released()); + EXPECT_FALSE(P.get()); + + P.reset(new int); + EXPECT_TRUE(P); + EXPECT_FALSE(P.released()); + EXPECT_TRUE(P.get()); +} + +TEST(UniquePtrDeferredRelease, Swap) { + unique_ptr_deferred_release P1(new int); + unique_ptr_deferred_release P2(new int); + P1.release(); + P1.swap(P2); + EXPECT_TRUE(P1); + EXPECT_FALSE(P1.released()); + EXPECT_TRUE(P1.get()); + EXPECT_TRUE(P2); + EXPECT_TRUE(P2.released()); + EXPECT_TRUE(P2.get()); + + delete P2.get(); +} +} // end anonymous namespace