forked from OSchip/llvm-project
Even more warnings utilizing gsl::Owner/gsl::Pointer annotations
Differential Revision: https://reviews.llvm.org/D65127 llvm-svn: 368454
This commit is contained in:
parent
8a21214174
commit
7c3c8ba8da
|
@ -6568,19 +6568,33 @@ 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() || !Callee->getIdentifier())
|
||||
if (!Callee->getParent()->isInStdNamespace())
|
||||
return false;
|
||||
if (!isRecordWithAttr<PointerAttr>(Callee->getThisObjectType()) &&
|
||||
!isRecordWithAttr<OwnerAttr>(Callee->getThisObjectType()))
|
||||
return false;
|
||||
if (!isRecordWithAttr<PointerAttr>(Callee->getReturnType()) &&
|
||||
!Callee->getReturnType()->isPointerType())
|
||||
return false;
|
||||
return llvm::StringSwitch<bool>(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<PointerAttr>(Callee->getReturnType())) {
|
||||
if (!Callee->getIdentifier())
|
||||
return false;
|
||||
return llvm::StringSwitch<bool>(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<bool>(Callee->getName())
|
||||
.Cases("front", "back", "at", true)
|
||||
.Default(false);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void handleGslAnnotatedTypes(IndirectLocalPath &Path, Expr *Call,
|
||||
|
@ -6600,6 +6614,12 @@ static void handleGslAnnotatedTypes(IndirectLocalPath &Path, Expr *Call,
|
|||
if (MD && shouldTrackImplicitObjectArg(MD))
|
||||
VisitPointerArg(MD, MCE->getImplicitObjectArgument());
|
||||
return;
|
||||
} else if (auto *OCE = dyn_cast<CXXOperatorCallExpr>(Call)) {
|
||||
FunctionDecl *Callee = OCE->getDirectCallee();
|
||||
if (Callee->isCXXInstanceMember() &&
|
||||
shouldTrackImplicitObjectArg(cast<CXXMethodDecl>(Callee)))
|
||||
VisitPointerArg(Callee, OCE->getArg(0));
|
||||
return;
|
||||
}
|
||||
|
||||
if (auto *CCE = dyn_cast<CXXConstructExpr>(Call)) {
|
||||
|
|
|
@ -121,24 +121,47 @@ void initLocalGslPtrWithTempOwner() {
|
|||
|
||||
namespace std {
|
||||
template <typename T>
|
||||
struct basic_iterator {};
|
||||
struct basic_iterator {
|
||||
basic_iterator operator++();
|
||||
T& operator*();
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
bool operator!=(basic_iterator<T>, basic_iterator<T>);
|
||||
|
||||
template <typename T>
|
||||
struct vector {
|
||||
typedef basic_iterator<T> iterator;
|
||||
iterator begin();
|
||||
iterator end();
|
||||
T *data();
|
||||
T &at(int n);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct basic_string_view {
|
||||
basic_string_view(const T *);
|
||||
const T *begin() const;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct basic_string {
|
||||
const T *c_str() const;
|
||||
operator basic_string_view<T> () const;
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct unique_ptr {
|
||||
T *get() const;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct optional {
|
||||
optional();
|
||||
optional(const T&);
|
||||
T &operator*();
|
||||
};
|
||||
}
|
||||
|
||||
void modelIterators() {
|
||||
|
@ -168,3 +191,29 @@ int *danglingUniquePtrFromTemp() {
|
|||
int *danglingUniquePtrFromTemp2() {
|
||||
return std::unique_ptr<int>().get(); // expected-warning {{returning address of local temporary object}}
|
||||
}
|
||||
|
||||
void danglingReferenceFromTempOwner() {
|
||||
int &r = *std::optional<int>(); // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}}
|
||||
int &r2 = *std::optional<int>(5); // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}}
|
||||
int &r3 = std::vector<int>().at(3); // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}}
|
||||
}
|
||||
|
||||
std::vector<int> getTempVec();
|
||||
std::optional<std::vector<int>> getTempOptVec();
|
||||
|
||||
int &usedToBeFalsePositive(std::vector<int> &v) {
|
||||
std::vector<int>::iterator it = v.begin();
|
||||
int& value = *it;
|
||||
return value; // ok
|
||||
}
|
||||
|
||||
int &doNotFollowReferencesForLocalOwner() {
|
||||
std::unique_ptr<int> localOwner;
|
||||
int &p = *localOwner.get();
|
||||
// In real world code localOwner is usually moved here.
|
||||
return p; // ok
|
||||
}
|
||||
|
||||
const char *trackThroughMultiplePointer() {
|
||||
return std::basic_string_view<char>(std::basic_string<char>()).begin(); // expected-warning {{returning address of local temporary object}}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue