r368871 - [LifetimeAnalysis] Fix false negatives of statement local lifetime analysis for some STL implementation
Gabor Horvath via cfe-commits
cfe-commits at lists.llvm.org
Wed Aug 14 09:34:56 PDT 2019
Author: xazax
Date: Wed Aug 14 09:34:56 2019
New Revision: 368871
URL: http://llvm.org/viewvc/llvm-project?rev=368871&view=rev
Log:
[LifetimeAnalysis] Fix false negatives of statement local lifetime analysis for some STL implementation
Differential Revision: https://reviews.llvm.org/D66152
Modified:
cfe/trunk/lib/Sema/SemaInit.cpp
cfe/trunk/test/Sema/warn-lifetime-analysis-nocfg.cpp
Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=368871&r1=368870&r2=368871&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Wed Aug 14 09:34:56 2019
@@ -16,6 +16,7 @@
#include "clang/AST/ExprObjC.h"
#include "clang/AST/ExprOpenMP.h"
#include "clang/AST/TypeLoc.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/Designator.h"
#include "clang/Sema/Initialization.h"
@@ -6564,11 +6565,29 @@ template <typename T> static bool isReco
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<NamespaceDecl>(DC))
+ if (const IdentifierInfo *II = ND->getIdentifier()) {
+ StringRef Name = II->getName();
+ if (Name.size() >= 2 && Name.front() == '_' &&
+ (Name[1] == '_' || isUppercase(Name[1])))
+ return true;
+ }
+
+ return DC->isStdNamespace();
+}
+
static bool shouldTrackImplicitObjectArg(const CXXMethodDecl *Callee) {
if (auto *Conv = dyn_cast_or_null<CXXConversionDecl>(Callee))
if (isRecordWithAttr<PointerAttr>(Conv->getConversionType()))
return true;
- if (!Callee->getParent()->isInStdNamespace())
+ if (!isInStlNamespace(Callee->getParent()))
return false;
if (!isRecordWithAttr<PointerAttr>(Callee->getThisObjectType()) &&
!isRecordWithAttr<OwnerAttr>(Callee->getThisObjectType()))
@@ -7107,25 +7126,29 @@ void Sema::checkInitializerLifetime(cons
SourceLocation DiagLoc = DiagRange.getBegin();
auto *MTE = dyn_cast<MaterializeTemporaryExpr>(L);
- bool IsTempGslOwner = MTE && !MTE->getExtendingDecl() &&
- isRecordWithAttr<OwnerAttr>(MTE->getType());
- bool IsLocalGslOwner =
- isa<DeclRefExpr>(L) && isRecordWithAttr<OwnerAttr>(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<DeclRefExpr>(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<OwnerAttr>(L->getType());
+ if (pathContainsInit(Path) || !IsLocalGslOwner)
+ return false;
+ } else {
+ IsGslPtrInitWithGslTempOwner = MTE && !MTE->getExtendingDecl() &&
+ isRecordWithAttr<OwnerAttr>(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:
Modified: cfe/trunk/test/Sema/warn-lifetime-analysis-nocfg.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/warn-lifetime-analysis-nocfg.cpp?rev=368871&r1=368870&r2=368871&view=diff
==============================================================================
--- cfe/trunk/test/Sema/warn-lifetime-analysis-nocfg.cpp (original)
+++ cfe/trunk/test/Sema/warn-lifetime-analysis-nocfg.cpp Wed Aug 14 09:34:56 2019
@@ -119,14 +119,7 @@ void initLocalGslPtrWithTempOwner() {
global2 = MyLongOwnerWithConversion{}; // TODO ?
}
-namespace std {
-template<class T> struct remove_reference { typedef T type; };
-template<class T> struct remove_reference<T &> { typedef T type; };
-template<class T> struct remove_reference<T &&> { typedef T type; };
-
-template<class T>
-typename remove_reference<T>::type &&move(T &&t) noexcept;
-
+namespace __gnu_cxx {
template <typename T>
struct basic_iterator {
basic_iterator operator++();
@@ -135,10 +128,19 @@ struct basic_iterator {
template<typename T>
bool operator!=(basic_iterator<T>, basic_iterator<T>);
+}
+
+namespace std {
+template<class T> struct remove_reference { typedef T type; };
+template<class T> struct remove_reference<T &> { typedef T type; };
+template<class T> struct remove_reference<T &&> { typedef T type; };
+
+template<class T>
+typename remove_reference<T>::type &&move(T &&t) noexcept;
template <typename T>
struct vector {
- typedef basic_iterator<T> iterator;
+ typedef __gnu_cxx::basic_iterator<T> iterator;
iterator begin();
iterator end();
const T *data() const;
More information about the cfe-commits
mailing list