Index: clang/lib/Sema/SemaInit.cpp =================================================================== --- clang/lib/Sema/SemaInit.cpp +++ clang/lib/Sema/SemaInit.cpp @@ -6564,16 +6564,30 @@ if (auto *Conv = dyn_cast_or_null(Callee)) if (isRecordWithAttr(Conv->getConversionType())) return true; - if (!Callee->getParent()->isInStdNamespace() || !Callee->getIdentifier()) + if (!Callee->getParent()->isInStdNamespace()) return false; - if (!isRecordWithAttr(Callee->getReturnType()) && - !Callee->getReturnType()->isPointerType()) - return false; - return llvm::StringSwitch(Callee->getName()) - .Cases("begin", "rbegin", "cbegin", "crbegin", true) - .Cases("end", "rend", "cend", "crend", true) - .Cases("c_str", "data", "get", true) - .Default(false); + if (Callee->getReturnType()->isPointerType() || + isRecordWithAttr(Callee->getReturnType())) { + if (!Callee->getIdentifier()) + return false; + return llvm::StringSwitch(Callee->getName()) + .Cases("begin", "rbegin", "cbegin", "crbegin", true) + .Cases("end", "rend", "cend", "crend", true) + .Cases("c_str", "data", "get", true) + // Map and set types. + .Cases("find", "equal_range", "lower_bound", "upper_bound", true) + .Default(false); + } else if (Callee->getReturnType()->isReferenceType()) { + if (!Callee->getIdentifier()) { + auto OO = Callee->getOverloadedOperator(); + return OO == OverloadedOperatorKind::OO_Subscript || + OO == OverloadedOperatorKind::OO_Star; + } + return llvm::StringSwitch(Callee->getName()) + .Cases("front", "back", "at", true) + .Default(false); + } + return false; } static void handleGslAnnotatedTypes(IndirectLocalPath &Path, Expr *Call, @@ -6607,12 +6621,18 @@ if (shouldTrackImplicitObjectArg(MD)) VisitPointerArg(MD, MCE->getImplicitObjectArgument()); return; + } else if (auto *OCE = dyn_cast(Call)) { + if (Callee->isCXXInstanceMember() && + shouldTrackImplicitObjectArg(cast(Callee))) + VisitPointerArg(Callee, OCE->getArg(0)); + return; } if (auto *CCE = dyn_cast(Call)) { const auto *Ctor = CCE->getConstructor(); const CXXRecordDecl *RD = Ctor->getParent()->getCanonicalDecl(); - if (RD->hasAttr() && isa(Call)) { + if (RD->hasAttr() && isa(Call) && + !Ctor->isCopyOrMoveConstructor()) { Path.push_back({IndirectLocalPathEntry::GslOwnerTemporaryInit, Call, RD}); Visit(Path, Call, RK_ReferenceBinding); Path.pop_back(); @@ -7120,11 +7140,11 @@ llvm_unreachable("already handled this"); case LK_Extended: { - auto *MTE = dyn_cast(L); if (IsGslPtrInitWithGslTempOwner) { Diag(DiagLoc, diag::warn_dangling_lifetime_pointer) << DiagRange; return false; } + auto *MTE = dyn_cast(L); if (!MTE) { // The initialized entity has lifetime beyond the full-expression, // and the local entity does too, so don't warn. Index: clang/test/Sema/warn-lifetime-analysis-nocfg.cpp =================================================================== --- clang/test/Sema/warn-lifetime-analysis-nocfg.cpp +++ clang/test/Sema/warn-lifetime-analysis-nocfg.cpp @@ -121,13 +121,21 @@ namespace std { template -struct basic_iterator {}; +struct basic_iterator { + basic_iterator operator++(); + T& operator*(); +}; + +template +bool operator!=(basic_iterator, basic_iterator); template struct vector { typedef basic_iterator iterator; iterator begin(); + iterator end(); T *data(); + T &at(int n); }; template @@ -139,6 +147,13 @@ struct unique_ptr { T *get() const; }; + +template +struct optional { + optional(); + optional(const T&); + T &operator*(); +}; } void modelIterators() { @@ -167,4 +182,20 @@ int *danglingUniquePtrFromTemp2() { return std::unique_ptr().get(); // expected-warning {{returning address of local temporary object}} +} + +void danglingReferenceFromTempOwner() { + int &r = *std::optional(); // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}} + int &r2 = *std::optional(5); // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}} + int &r3 = std::vector().at(3); // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}} +} + +std::vector getTempVec(); +std::optional> getTempOptVec(); + +void testLoops() { + for (auto i : getTempVec()) // ok + ; + for (auto i : *getTempOptVec()) // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}} + ; } \ No newline at end of file