Index: include/llvm/ADT/STLExtras.h =================================================================== --- include/llvm/ADT/STLExtras.h +++ include/llvm/ADT/STLExtras.h @@ -195,6 +195,12 @@ adl_detail::adl_swap(std::forward(lhs), std::forward(rhs)); } +/// Test whether \p RangeOrContainer is empty. Similar to C++17 std::empty. +template +constexpr bool empty(const T &RangeOrContainer) { + return adl_begin(RangeOrContainer) == adl_end(RangeOrContainer); +} + // mapped_iterator - This is a simple iterator adapter that causes a function to // be applied whenever operator* is invoked on the iterator. Index: lib/Analysis/LazyCallGraph.cpp =================================================================== --- lib/Analysis/LazyCallGraph.cpp +++ lib/Analysis/LazyCallGraph.cpp @@ -619,7 +619,7 @@ // If the merge range is empty, then adding the edge didn't actually form any // new cycles. We're done. - if (MergeRange.begin() == MergeRange.end()) { + if (empty(MergeRange)) { // Now that the SCC structure is finalized, flip the kind to call. SourceN->setEdgeKind(TargetN, Edge::Call); return false; // No new cycle. Index: lib/CodeGen/GlobalISel/InstructionSelector.cpp =================================================================== --- lib/CodeGen/GlobalISel/InstructionSelector.cpp +++ lib/CodeGen/GlobalISel/InstructionSelector.cpp @@ -80,5 +80,5 @@ return true; return !MI.mayLoadOrStore() && !MI.hasUnmodeledSideEffects() && - MI.implicit_operands().begin() == MI.implicit_operands().end(); + empty(MI.implicit_operands()); } Index: lib/CodeGen/GlobalISel/LegalizerInfo.cpp =================================================================== --- lib/CodeGen/GlobalISel/LegalizerInfo.cpp +++ lib/CodeGen/GlobalISel/LegalizerInfo.cpp @@ -298,8 +298,7 @@ std::initializer_list Opcodes) { unsigned Representative = *Opcodes.begin(); - assert(Opcodes.begin() != Opcodes.end() && - Opcodes.begin() + 1 != Opcodes.end() && + assert(!empty(Opcodes) && Opcodes.begin() + 1 != Opcodes.end() && "Initializer list must have at least two opcodes"); for (auto I = Opcodes.begin() + 1, E = Opcodes.end(); I != E; ++I) Index: lib/CodeGen/GlobalISel/RegBankSelect.cpp =================================================================== --- lib/CodeGen/GlobalISel/RegBankSelect.cpp +++ lib/CodeGen/GlobalISel/RegBankSelect.cpp @@ -140,7 +140,7 @@ return false; assert(ValMapping.NumBreakDowns == 1 && "Not yet implemented"); // An empty range of new register means no repairing. - assert(NewVRegs.begin() != NewVRegs.end() && "We should not have to repair"); + assert(!empty(NewVRegs) && "We should not have to repair"); // Assume we are repairing a use and thus, the original reg will be // the source of the repairing. Index: lib/CodeGen/GlobalISel/RegisterBankInfo.cpp =================================================================== --- lib/CodeGen/GlobalISel/RegisterBankInfo.cpp +++ lib/CodeGen/GlobalISel/RegisterBankInfo.cpp @@ -426,7 +426,7 @@ "This mapping is too complex for this function"); iterator_range::const_iterator> NewRegs = OpdMapper.getVRegs(OpIdx); - if (NewRegs.begin() == NewRegs.end()) { + if (empty(NewRegs)) { LLVM_DEBUG(dbgs() << " has not been repaired, nothing to be done\n"); continue; } Index: lib/ExecutionEngine/Orc/ExecutionUtils.cpp =================================================================== --- lib/ExecutionEngine/Orc/ExecutionUtils.cpp +++ lib/ExecutionEngine/Orc/ExecutionUtils.cpp @@ -88,7 +88,7 @@ } void CtorDtorRunner::add(iterator_range CtorDtors) { - if (CtorDtors.begin() == CtorDtors.end()) + if (empty(CtorDtors)) return; MangleAndInterner Mangle( Index: lib/IR/DebugInfo.cpp =================================================================== --- lib/IR/DebugInfo.cpp +++ lib/IR/DebugInfo.cpp @@ -280,7 +280,7 @@ } static MDNode *stripDebugLocFromLoopID(MDNode *N) { - assert(N->op_begin() != N->op_end() && "Missing self reference?"); + assert(!empty(N->operands()) && "Missing self reference?"); // if there is no debug location, we do not have to rewrite this MDNode. if (std::none_of(N->op_begin() + 1, N->op_end(), [](const MDOperand &Op) { Index: lib/Transforms/IPO/PartialInlining.cpp =================================================================== --- lib/Transforms/IPO/PartialInlining.cpp +++ lib/Transforms/IPO/PartialInlining.cpp @@ -1251,7 +1251,7 @@ if (PSI->isFunctionEntryCold(F)) return {false, nullptr}; - if (F->user_begin() == F->user_end()) + if (empty(F->users())) return {false, nullptr}; OptimizationRemarkEmitter ORE(F); @@ -1357,7 +1357,7 @@ return false; } - assert(Cloner.OrigFunc->user_begin() == Cloner.OrigFunc->user_end() && + assert(empty(Cloner.OrigFunc->users()) && "F's users should all be replaced!"); std::vector Users(Cloner.ClonedFunc->user_begin(), Index: lib/Transforms/Scalar/NewGVN.cpp =================================================================== --- lib/Transforms/Scalar/NewGVN.cpp +++ lib/Transforms/Scalar/NewGVN.cpp @@ -1751,7 +1751,7 @@ return true; }); // If we are left with no operands, it's dead. - if (Filtered.begin() == Filtered.end()) { + if (empty(Filtered)) { // If it has undef at this point, it means there are no-non-undef arguments, // and thus, the value of the phi node must be undef. if (HasUndef) { Index: lib/Transforms/Utils/PredicateInfo.cpp =================================================================== --- lib/Transforms/Utils/PredicateInfo.cpp +++ lib/Transforms/Utils/PredicateInfo.cpp @@ -522,7 +522,7 @@ if (isa(ValInfo)) { IRBuilder<> B(getBranchTerminator(ValInfo)); Function *IF = getCopyDeclaration(F.getParent(), Op->getType()); - if (IF->user_begin() == IF->user_end()) + if (empty(IF->users())) CreatedDeclarations.insert(IF); CallInst *PIC = B.CreateCall(IF, Op, Op->getName() + "." + Twine(Counter++)); @@ -534,7 +534,7 @@ "Should not have gotten here without it being an assume"); IRBuilder<> B(PAssume->AssumeInst); Function *IF = getCopyDeclaration(F.getParent(), Op->getType()); - if (IF->user_begin() == IF->user_end()) + if (empty(IF->users())) CreatedDeclarations.insert(IF); CallInst *PIC = B.CreateCall(IF, Op); PredicateMap.insert({PIC, ValInfo}); Index: lib/Transforms/Utils/SimplifyCFG.cpp =================================================================== --- lib/Transforms/Utils/SimplifyCFG.cpp +++ lib/Transforms/Utils/SimplifyCFG.cpp @@ -5260,7 +5260,7 @@ // Figure out the corresponding result for each case value and phi node in the // common destination, as well as the min and max case values. - assert(SI->case_begin() != SI->case_end()); + assert(!empty(SI->cases())); SwitchInst::CaseIt CI = SI->case_begin(); ConstantInt *MinCaseVal = CI->getCaseValue(); ConstantInt *MaxCaseVal = CI->getCaseValue(); Index: unittests/ADT/STLExtrasTest.cpp =================================================================== --- unittests/ADT/STLExtrasTest.cpp +++ unittests/ADT/STLExtrasTest.cpp @@ -364,6 +364,23 @@ EXPECT_EQ(5, count); } +TEST(STLExtrasTest, EmptyTest) { + std::vector V; + EXPECT_TRUE(empty(V)); + V.push_back(nullptr); + EXPECT_FALSE(empty(V)); + + std::initializer_list E = {}; + std::initializer_list NotE = {7, 13, 42}; + EXPECT_TRUE(empty(E)); + EXPECT_FALSE(empty(NotE)); + + auto R0 = make_range(V.begin(), V.begin()); + EXPECT_TRUE(empty(R0)); + auto R1 = make_range(V.begin(), V.end()); + EXPECT_FALSE(empty(R1)); +} + TEST(STLExtrasTest, EarlyIncrementTest) { std::list L = {1, 2, 3, 4};