diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -6565,11 +6565,29 @@ return false; } +// Decl::isInStdNamespace will return false for iterators in some STL +// implementations due to them being defined in a namespace outside of the std +// namespace. +static bool isInStlNamespace(const Decl *D) { + const DeclContext *DC = D->getDeclContext(); + if (!DC) + return false; + if (const auto *ND = dyn_cast(DC)) + if (const IdentifierInfo *II = ND->getIdentifier()) { + StringRef Name = II->getName(); + if (Name.size() >= 2 && Name.front() == '_' && + (Name[1] == '_' || llvm::toUpper(Name[1]) == Name[1])) + return true; + } + + return DC->isStdNamespace(); +} + static bool shouldTrackImplicitObjectArg(const CXXMethodDecl *Callee) { if (auto *Conv = dyn_cast_or_null(Callee)) if (isRecordWithAttr(Conv->getConversionType())) return true; - if (!Callee->getParent()->isInStdNamespace()) + if (!isInStlNamespace(Callee->getParent())) return false; if (!isRecordWithAttr(Callee->getThisObjectType()) && !isRecordWithAttr(Callee->getThisObjectType())) @@ -7108,25 +7126,29 @@ SourceLocation DiagLoc = DiagRange.getBegin(); auto *MTE = dyn_cast(L); - bool IsTempGslOwner = MTE && !MTE->getExtendingDecl() && - isRecordWithAttr(MTE->getType()); - bool IsLocalGslOwner = - isa(L) && isRecordWithAttr(L->getType()); - - // Skipping a chain of initializing gsl::Pointer annotated objects. - // We are looking only for the final source to find out if it was - // a local or temporary owner or the address of a local variable/param. We - // do not want to follow the references when returning a pointer originating - // from a local owner to avoid the following false positive: - // int &p = *localUniquePtr; - // someContainer.add(std::move(localUniquePtr)); - // return p; - if (!IsTempGslOwner && pathOnlyInitializesGslPointer(Path) && - !(IsLocalGslOwner && !pathContainsInit(Path))) - return true; - bool IsGslPtrInitWithGslTempOwner = - IsTempGslOwner && pathOnlyInitializesGslPointer(Path); + bool IsGslPtrInitWithGslTempOwner = false; + bool IsLocalGslOwner = false; + if (pathOnlyInitializesGslPointer(Path)) { + if (isa(L)) { + // We do not want to follow the references when returning a pointer originating + // from a local owner to avoid the following false positive: + // int &p = *localUniquePtr; + // someContainer.add(std::move(localUniquePtr)); + // return p; + IsLocalGslOwner = isRecordWithAttr(L->getType()); + if (pathContainsInit(Path) || !IsLocalGslOwner) + return false; + } else { + IsGslPtrInitWithGslTempOwner = MTE && !MTE->getExtendingDecl() && + isRecordWithAttr(MTE->getType()); + // Skipping a chain of initializing gsl::Pointer annotated objects. + // We are looking only for the final source to find out if it was + // a local or temporary owner or the address of a local variable/param. + if (!IsGslPtrInitWithGslTempOwner) + return true; + } + } switch (LK) { case LK_FullExpression: diff --git a/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp b/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp --- a/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp +++ b/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp @@ -119,14 +119,7 @@ global2 = MyLongOwnerWithConversion{}; // TODO ? } -namespace std { -template struct remove_reference { typedef T type; }; -template struct remove_reference { typedef T type; }; -template struct remove_reference { typedef T type; }; - -template -typename remove_reference::type &&move(T &&t) noexcept; - +namespace __gnu_cxx { template struct basic_iterator { basic_iterator operator++(); @@ -135,10 +128,19 @@ template bool operator!=(basic_iterator, basic_iterator); +} + +namespace std { +template struct remove_reference { typedef T type; }; +template struct remove_reference { typedef T type; }; +template struct remove_reference { typedef T type; }; + +template +typename remove_reference::type &&move(T &&t) noexcept; template struct vector { - typedef basic_iterator iterator; + typedef __gnu_cxx::basic_iterator iterator; iterator begin(); iterator end(); const T *data() const;