diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 57784a4ba2e38..21cfd69dc69fc 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2029,6 +2029,10 @@ def warn_frame_address : Warning< "calling '%0' with a nonzero argument is unsafe">, InGroup, DefaultIgnore; +def warn_frame_address_missing_noinline: Warning< + "calling '%0' in function not marked __attribute__((noinline)) may return a caller's %1 address">, + InGroup, DefaultIgnore; + def warn_cxx98_compat_nontrivial_union_or_anon_struct_member : Warning< "%select{anonymous struct|union}0 member %1 with a non-trivial " "%sub{select_special_member_kind}2 is incompatible with C++98">, diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 984088e345c80..3c0a5a8a402ae 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -2730,17 +2730,33 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, if (SemaBuiltinConstantArgRange(TheCall, 0, 0, 0xFFFF)) return ExprError(); - // -Wframe-address warning if non-zero passed to builtin - // return/frame address. Expr::EvalResult Result; if (!TheCall->getArg(0)->isValueDependent() && - TheCall->getArg(0)->EvaluateAsInt(Result, getASTContext()) && - Result.Val.getInt() != 0) - Diag(TheCall->getBeginLoc(), diag::warn_frame_address) - << ((BuiltinID == Builtin::BI__builtin_return_address) - ? "__builtin_return_address" - : "__builtin_frame_address") - << TheCall->getSourceRange(); + TheCall->getArg(0)->EvaluateAsInt(Result, getASTContext())) { + const char *BuiltinName = + (BuiltinID == Builtin::BI__builtin_return_address) + ? "__builtin_return_address" + : "__builtin_frame_address"; + + // -Wframe-address warning if non-zero passed to builtin + // return/frame address. + if (Result.Val.getInt() != 0) { + Diag(TheCall->getBeginLoc(), diag::warn_frame_address) + << BuiltinName << TheCall->getSourceRange(); + } + + // -Wframe-address warning if enclosing function is not marked noinline. + if (const FunctionDecl *FD = dyn_cast(CurContext)) { + if (!FD->hasAttr() && !FD->isMain()) { + const char *ShortName = + (BuiltinID == Builtin::BI__builtin_return_address) ? "return" + : "frame"; + Diag(TheCall->getBeginLoc(), + diag::warn_frame_address_missing_noinline) + << BuiltinName << ShortName << TheCall->getSourceRange(); + } + } + } break; } diff --git a/clang/test/Sema/builtin-returnaddress.c b/clang/test/Sema/builtin-returnaddress.c index 16d2a517ac12f..0b6733f9381c9 100644 --- a/clang/test/Sema/builtin-returnaddress.c +++ b/clang/test/Sema/builtin-returnaddress.c @@ -2,24 +2,32 @@ // RUN: %clang_cc1 -fsyntax-only -Wmost -verify %s // RUN: %clang_cc1 -x c++ -fsyntax-only -Wframe-address -verify %s -void* a(unsigned x) { +__attribute__((noinline)) void* a(unsigned x) { return __builtin_return_address(0); } -void* b(unsigned x) { +__attribute__((noinline)) void* b(unsigned x) { return __builtin_return_address(1); // expected-warning{{calling '__builtin_return_address' with a nonzero argument is unsafe}} } -void* c(unsigned x) { +__attribute__((noinline)) void* c(unsigned x) { return __builtin_frame_address(0); } -void* d(unsigned x) { +__attribute__((noinline)) void* d(unsigned x) { return __builtin_frame_address(1); // expected-warning{{calling '__builtin_frame_address' with a nonzero argument is unsafe}} } +void* e(unsigned x) { + return __builtin_frame_address(0); // expected-warning{{calling '__builtin_frame_address' in function not marked __attribute__((noinline)) may return a caller's frame address}} +} + +void* f(unsigned x) { + return __builtin_return_address(0); // expected-warning{{calling '__builtin_return_address' in function not marked __attribute__((noinline)) may return a caller's return address}} +} + #ifdef __cplusplus -template void *RA() +template __attribute__((noinline)) void *RA() { return __builtin_return_address(N); // expected-warning{{calling '__builtin_return_address' with a nonzero argument is unsafe}} } @@ -28,4 +36,28 @@ void *foo() { return RA<2>(); // expected-note{{in instantiation of function template specialization 'RA<2>' requested here}} } -#endif + +void* f() { + return ([&] () { + return __builtin_frame_address(0); // expected-warning{{calling '__builtin_frame_address' in function not marked __attribute__((noinline)) may return a caller's frame address}} + })(); +} + +void* g() { + return ([&] () __attribute__((noinline)) { + return __builtin_frame_address(0); + })(); +} + +void* h() { + return ([&] () { + return __builtin_return_address(0); // expected-warning{{calling '__builtin_return_address' in function not marked __attribute__((noinline)) may return a caller's return address}} + })(); +} + +void* i() { + return ([&] () __attribute__((noinline)) { + return __builtin_return_address(0); + })(); +} +#endif \ No newline at end of file