Fix two false positives in -Wreturn-stack-address

If the return type is a pointer and the function returns the reference to a
pointer, don't warn since only the value is returned, not the reference.

If a reference function parameter appears in the reference chain, don't warn
since binding happens at the caller scope, so addresses returned are not
to local stack.  This includes default arguments as well.

llvm-svn: 277889
This commit is contained in:
Richard Trieu 2016-08-05 23:24:47 +00:00
parent 9e91c28b71
commit 81b6c561ea
2 changed files with 76 additions and 1 deletions

View File

@ -6572,6 +6572,12 @@ CheckReturnStackAddr(Sema &S, Expr *RetValExp, QualType lhsType,
if (!stackE) if (!stackE)
return; // Nothing suspicious was found. return; // Nothing suspicious was found.
// Parameters are initalized in the calling scope, so taking the address
// of a parameter reference doesn't need a warning.
for (auto *DRE : refVars)
if (isa<ParmVarDecl>(DRE->getDecl()))
return;
SourceLocation diagLoc; SourceLocation diagLoc;
SourceRange diagRange; SourceRange diagRange;
if (refVars.empty()) { if (refVars.empty()) {
@ -6595,6 +6601,13 @@ CheckReturnStackAddr(Sema &S, Expr *RetValExp, QualType lhsType,
} else if (isa<AddrLabelExpr>(stackE)) { // address of label. } else if (isa<AddrLabelExpr>(stackE)) { // address of label.
S.Diag(diagLoc, diag::warn_ret_addr_label) << diagRange; S.Diag(diagLoc, diag::warn_ret_addr_label) << diagRange;
} else { // local temporary. } else { // local temporary.
// If there is an LValue->RValue conversion, then the value of the
// reference type is used, not the reference.
if (auto *ICE = dyn_cast<ImplicitCastExpr>(RetValExp)) {
if (ICE->getCastKind() == CK_LValueToRValue) {
return;
}
}
S.Diag(diagLoc, diag::warn_ret_local_temp_addr_ref) S.Diag(diagLoc, diag::warn_ret_local_temp_addr_ref)
<< lhsType->isReferenceType() << diagRange; << lhsType->isReferenceType() << diagRange;
} }

View File

@ -1,5 +1,4 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -std=c++11 %s // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -std=c++11 %s
// expected-no-diagnostics
namespace PR26599 { namespace PR26599 {
template <typename> template <typename>
@ -20,3 +19,66 @@ void *&pointer() {
} }
} }
namespace LocalTemporary {
template <class T>
class QMap {
public:
T value(const T &t = T()) const {
return t;
}
};
struct A {};
void test() {
QMap<A *> map;
map.value();
}
typedef int* ptr;
ptr int1(const ptr &p = ptr()) {
return (p);
}
ptr int2(const ptr &p = nullptr) {
return p;
}
ptr int3() {
const ptr &p = ptr();
return p;
}
const int *int4(const int &x = 5) {
return &x;
}
const int *int5(const int &x) {
return &x;
}
const int *int6() {
const int &x = 11; //expected-note{{binding reference variable 'x' here}}
return &x; //expected-warning{{returning address of local temporary object}}
}
const int *int7(int x) {
const int &x2 = x; // expected-note{{binding reference variable 'x2' here}}
const int &x3 = x2;
return &x2; // expected-warning{{address of stack memory associated with local variable 'x' returned}}
}
const int *int8(const int &x = 5) {
const int &x2 = x;
const int &x3 = x2;
return &x2;
}
const int *int9() {
const int &x = 5; // expected-note{{binding reference variable 'x' here}}
const int &x2 = x; // expected-note{{binding reference variable 'x2' here}}
const int &x3 = x2;
return &x2; // expected-warning{{returning address of local temporary object}}
}
}