From 81b6c561eaeb2a48318523a037e6903d34f5fec3 Mon Sep 17 00:00:00 2001 From: Richard Trieu Date: Fri, 5 Aug 2016 23:24:47 +0000 Subject: [PATCH] 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 --- clang/lib/Sema/SemaChecking.cpp | 13 ++++++ clang/test/SemaCXX/return-stack-addr-2.cpp | 64 +++++++++++++++++++++++++++++- 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 2ca3d12..fd90121 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -6572,6 +6572,12 @@ CheckReturnStackAddr(Sema &S, Expr *RetValExp, QualType lhsType, if (!stackE) 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(DRE->getDecl())) + return; + SourceLocation diagLoc; SourceRange diagRange; if (refVars.empty()) { @@ -6595,6 +6601,13 @@ CheckReturnStackAddr(Sema &S, Expr *RetValExp, QualType lhsType, } else if (isa(stackE)) { // address of label. S.Diag(diagLoc, diag::warn_ret_addr_label) << diagRange; } 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(RetValExp)) { + if (ICE->getCastKind() == CK_LValueToRValue) { + return; + } + } S.Diag(diagLoc, diag::warn_ret_local_temp_addr_ref) << lhsType->isReferenceType() << diagRange; } diff --git a/clang/test/SemaCXX/return-stack-addr-2.cpp b/clang/test/SemaCXX/return-stack-addr-2.cpp index ad27567..f6ea9b2 100644 --- a/clang/test/SemaCXX/return-stack-addr-2.cpp +++ b/clang/test/SemaCXX/return-stack-addr-2.cpp @@ -1,5 +1,4 @@ // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -std=c++11 %s -// expected-no-diagnostics namespace PR26599 { template @@ -20,3 +19,66 @@ void *&pointer() { } } +namespace LocalTemporary { + +template +class QMap { +public: + T value(const T &t = T()) const { + return t; + } +}; + +struct A {}; + +void test() { + QMap 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}} +} +} -- 2.7.4