@@ -693,6 +693,14 @@ Does nothing. Preserved for backward com
Wmissing-noreturn
Common Warning Alias(Wsuggest-attribute=noreturn)
+Wmusttail-local-addr
+Common Var(warn_musttail_local_addr) Init(1) Warning
+Warn about passing a pointer/reference to a local or temporary variable to a musttail call argument.
+
+Wmaybe-musttail-local-addr
+Common Var(warn_maybe_musttail_local_addr) Warning EnabledBy(Wextra)
+Warn about pointer/reference to a local or temporary variable possibly escaping to a musttail call.
+
Wodr
Common Var(warn_odr_violations) Init(1) Warning
Warn about some C++ One Definition Rule violations during link time optimization.
@@ -206,14 +206,48 @@ suitable_for_tail_call_opt_p (gcall *cal
/* ??? It is OK if the argument of a function is taken in some cases,
but not in all cases. See PR15387 and PR19616. Revisit for 4.1. */
- for (param = DECL_ARGUMENTS (current_function_decl);
- param;
- param = DECL_CHAIN (param))
- if (TREE_ADDRESSABLE (param))
+ if (!diag_musttail || !gimple_call_must_tail_p (call))
+ for (param = DECL_ARGUMENTS (current_function_decl);
+ param; param = DECL_CHAIN (param))
+ if (TREE_ADDRESSABLE (param))
+ {
+ maybe_error_musttail (call, _("address of caller arguments taken"),
+ diag_musttail);
+ return false;
+ }
+
+ if (diag_musttail
+ && gimple_call_must_tail_p (call)
+ && warn_musttail_local_addr)
+ for (unsigned int i = 0; i < gimple_call_num_args (call); i++)
{
- maybe_error_musttail (call, _("address of caller arguments taken"),
- diag_musttail);
- return false;
+ tree arg = gimple_call_arg (call, i);
+ if (!POINTER_TYPE_P (TREE_TYPE (arg)))
+ continue;
+ if (TREE_CODE (arg) == ADDR_EXPR)
+ {
+ arg = get_base_address (TREE_OPERAND (arg, 0));
+ if (auto_var_in_fn_p (arg, current_function_decl))
+ {
+ if (TREE_CODE (arg) == LABEL_DECL)
+ warning_at (gimple_location (call), OPT_Wmusttail_local_addr,
+ "address of label passed to %<musttail%> "
+ "call argument");
+ else if (TREE_CODE (arg) == PARM_DECL)
+ warning_at (gimple_location (call), OPT_Wmusttail_local_addr,
+ "address of parameter %qD passed to "
+ "%<musttail%> call argument", arg);
+ else if (!DECL_ARTIFICIAL (arg) && DECL_NAME (arg))
+ warning_at (gimple_location (call), OPT_Wmusttail_local_addr,
+ "address of automatic variable %qD passed to "
+ "%<musttail%> call argument", arg);
+ else
+ warning_at (gimple_location (call), OPT_Wmusttail_local_addr,
+ "address of local variable passed to "
+ "%<musttail%> call argument");
+ suppress_warning (call, OPT_Wmaybe_musttail_local_addr);
+ }
+ }
}
return true;
@@ -443,7 +477,7 @@ maybe_error_musttail (gcall *call, const
{
if (gimple_call_must_tail_p (call) && diag_musttail)
{
- error_at (call->location, "cannot tail-call: %s", err);
+ error_at (gimple_location (call), "cannot tail-call: %s", err);
/* Avoid another error. ??? If there are multiple reasons why tail
calls fail it might be useful to report them all to avoid
whack-a-mole for the user. But currently there is too much
@@ -727,6 +761,19 @@ find_tail_calls (basic_block bb, struct
{
if (!VAR_P (var))
{
+ if (diag_musttail && gimple_call_must_tail_p (call))
+ {
+ auto opt = OPT_Wmaybe_musttail_local_addr;
+ if (!warning_suppressed_p (call,
+ opt))
+ {
+ warning_at (gimple_location (call), opt,
+ "address of local variable can escape to "
+ "%<musttail%> call");
+ suppress_warning (call, opt);
+ }
+ continue;
+ }
if (local_live_vars)
BITMAP_FREE (local_live_vars);
maybe_error_musttail (call,
@@ -739,6 +786,24 @@ find_tail_calls (basic_block bb, struct
unsigned int *v = live_vars->get (DECL_UID (var));
if (bitmap_bit_p (local_live_vars, *v))
{
+ if (diag_musttail && gimple_call_must_tail_p (call))
+ {
+ auto opt = OPT_Wmaybe_musttail_local_addr;
+ if (!warning_suppressed_p (call, opt))
+ {
+ if (!DECL_ARTIFICIAL (var) && DECL_NAME (var))
+ warning_at (gimple_location (call), opt,
+ "address of automatic variable %qD "
+ "can escape to %<musttail%> call",
+ var);
+ else
+ warning_at (gimple_location (call), opt,
+ "address of local variable can escape "
+ "to %<musttail%> call");
+ suppress_warning (call, opt);
+ }
+ continue;
+ }
BITMAP_FREE (local_live_vars);
maybe_error_musttail (call,
_("call invocation refers to locals"),
@@ -748,6 +813,22 @@ find_tail_calls (basic_block bb, struct
}
}
}
+ if (diag_musttail
+ && gimple_call_must_tail_p (call)
+ && !warning_suppressed_p (call, OPT_Wmaybe_musttail_local_addr))
+ for (tree param = DECL_ARGUMENTS (current_function_decl);
+ param; param = DECL_CHAIN (param))
+ if (may_be_aliased (param)
+ && (ref_maybe_used_by_stmt_p (call, param, false)
+ || call_may_clobber_ref_p (call, param, false)))
+ {
+ auto opt = OPT_Wmaybe_musttail_local_addr;
+ warning_at (gimple_location (call), opt,
+ "address of parameter %qD can escape to "
+ "%<musttail%> call", param);
+ suppress_warning (call, opt);
+ break;
+ }
if (local_live_vars)
BITMAP_FREE (local_live_vars);
@@ -157,6 +157,12 @@ UrlSuffix(gcc/Warning-Options.html#index
Wmissing-noreturn
UrlSuffix(gcc/Warning-Options.html#index-Wmissing-noreturn)
+Wmusttail-local-addr
+UrlSuffix(gcc/Warning-Options.html#index-Wno-musttail-local-addr)
+
+Wmaybe-musttail-local-addr
+UrlSuffix(gcc/Warning-Options.html#index-Wmaybe-musttail-local-addr)
+
Wodr
UrlSuffix(gcc/Warning-Options.html#index-Wno-odr)
@@ -9282,10 +9282,51 @@ __attribute__((musttail)) return bar();
If the compiler cannot generate a @code{musttail} tail call it will report
an error. On some targets tail calls may never be supported.
-Tail calls cannot reference locals in memory, which may affect
-builds without optimization when passing small structures, or passing
-or returning large structures. Enabling @option{-O1} or @option{-O2} can
-improve the success of tail calls.
+The user asserts for @code{musttail} tail calls that lifetime of automatic
+variables, function parameters and temporaries (unless they have non-trivial
+destruction) can end before the actual call instruction and that any access
+to those from inside of the called function results is considered undefined
+behavior. Enabling @option{-O1} or @option{-O2} can improve the success of
+tail calls.
+
+@smallexample
+int foo (int *);
+void bar (int *);
+struct S @{ S (); ~S (); int s; @};
+
+int
+baz (int *x)
+@{
+ if (*x == 1)
+ @{
+ int a = 42;
+ /* The call will be tail called (would not be without the
+ attribute), dereferencing the pointer in the callee is
+ undefined behavior and there will be a warning emitted
+ for this by default (@option{-Wmusttail-local-addr}). */
+ [[gnu::musttail]] return foo (&a);
+ @}
+ else if (*x == 2)
+ @{
+ int a = 42;
+ bar (&a);
+ /* The call will be tail called (would not be without the
+ attribute), if bar stores the pointer anywhere, dereferencing
+ it in foo will be undefined behavior and there will be a warning
+ emitted for this with @option{-Wextra}, which implies
+ @option{-Wmaybe-musttail-local-addr}. */
+ [[gnu::musttail]] return foo (nullptr);
+ @}
+ else
+ @{
+ S s;
+ /* The s variable requires non-trivial destruction which ought
+ to be performed after the foo call returns, so this will
+ be rejected. */
+ [[gnu::musttail]] return foo (&s.s);
+ @}
+@}
+@end smallexample
@end table
@node Attribute Syntax
@@ -394,7 +394,8 @@ Objective-C and Objective-C++ Dialects}.
-Wmemset-elt-size -Wmemset-transposed-args
-Wmisleading-indentation -Wmissing-attributes -Wmissing-braces
-Wmissing-field-initializers -Wmissing-format-attribute
--Wmissing-include-dirs -Wmissing-noreturn -Wno-missing-profile
+-Wmissing-include-dirs -Wmissing-noreturn -Wmusttail-local-addr
+-Wmaybe-musttail-local-addr -Wno-missing-profile
-Wno-multichar -Wmultistatement-macros -Wnonnull -Wnonnull-compare
-Wnormalized=@r{[}none@r{|}id@r{|}nfc@r{|}nfkc@r{]}
-Wnull-dereference -Wno-odr
@@ -6967,6 +6968,55 @@ is only active when @option{-fdelete-nul
which is enabled by optimizations in most targets. The precision of
the warnings depends on the optimization options used.
+@opindex Wno-musttail-local-addr
+@opindex -Wmusttail-local-addr
+@item -Wno-musttail-local-addr
+Do not warn about passing a pointer (or in C++, a reference) to a
+local variable or label to argument of a @code{musttail} call. Those
+variables go out of scope before the tail call instruction.
+
+@opindex Wmaybe-musttail-local-addr
+@opindex -Wno-maybe-musttail-local-addr
+@item -Wmaybe-musttail-local-addr
+Warn when address of a local variable can escape to a @code{musttail}
+call, unless it goes out of scope already before the @code{musttail}
+call.
+
+@smallexample
+int foo (int *);
+
+int
+bar (int *x)
+@{
+ if (x[0] == 1)
+ @{
+ int a = 42;
+ foo (&a);
+ /* Without the @code{musttail} attribute this call would not
+ be tail called, because address of the @code{a} variable escapes
+ and the second foo call could dereference it. With the attribute
+ the local variables are assumed to go out of scope immediately
+ before the tail call instruction and the compiler warns about
+ this. */
+ [[gnu::musttail]] return foo (nullptr);
+ @}
+ else
+ @{
+ @{
+ int a = 42;
+ foo (&a);
+ @}
+ /* The @code{a} variable isn't already in scope, so even when it
+ escaped, even without @code{musttail} attribute it would be
+ undefined behavior to dereference it and the compiler could
+ turn this into a tail call. No warning is diagnosed here. */
+ [[gnu::musttail]] return foo (nullptr);
+ @}
+@}
+@end smallexample
+
+This warning is enabled by @option{-Wextra}.
+
@opindex Wnrvo
@opindex Wno-nrvo
@item -Wnrvo @r{(C++ and Objective-C++ only)}
@@ -10,8 +10,9 @@ int f2(void)
int f3(int *);
-int f4(void)
+int f4(int *p)
{
int x;
- [[gnu::musttail]] return f3(&x); /* { dg-error "\(refers to locals|other reasons\)" } */
+ (void) p;
+ [[gnu::musttail]] return f3(&x); /* { dg-warning "address of automatic variable 'x' passed to 'musttail' call argument" } */
}
@@ -1,4 +1,4 @@
-/* { dg-do compile { target { musttail && { c || c++11 } } } } */
+/* { dg-do compile { target musttail } } */
/* { dg-additional-options "-fdelayed-branch" { target sparc*-*-* } } */
int __attribute__((noinline,noclone,noipa))
@@ -1,4 +1,4 @@
-/* { dg-do compile { target { musttail && { c || c++11 } } } } */
+/* { dg-do compile { target musttail } } */
struct box { char field[256]; int i; };
@@ -1,4 +1,4 @@
-/* { dg-do compile { target { musttail && { c || c++11 } } } } */
+/* { dg-do compile { target musttail } } */
struct box { char field[64]; int i; };
@@ -1,4 +1,4 @@
-/* { dg-do compile { target { musttail && { c || c++11 } } } } */
+/* { dg-do compile { target musttail } } */
/* { dg-additional-options "-fdelayed-branch" { target sparc*-*-* } } */
void __attribute__((noipa)) f() {}
@@ -1,4 +1,4 @@
-/* { dg-do compile { target { musttail && { c || c++11 } } } } */
+/* { dg-do compile { target musttail } } */
float f1(void);
@@ -10,8 +10,9 @@ int f2(void)
int f3(int *);
-int f4(void)
+int f4(int *p)
{
int x;
- __attribute__((musttail)) return f3(&x); /* { dg-error "\(refers to locals|other reasons\)" } */
+ (void) p;
+ __attribute__((musttail)) return f3(&x); /* { dg-warning "address of automatic variable 'x' passed to 'musttail' call argument" } */
}
@@ -1,4 +1,4 @@
-/* { dg-do compile { target { struct_musttail && { c || c++11 } } } } */
+/* { dg-do compile { target struct_musttail } } */
/* { dg-additional-options "-fdelayed-branch" { target sparc*-*-* } } */
struct str
@@ -1,4 +1,4 @@
-/* { dg-do compile { target { c || c++11 } } } */
+/* { dg-do compile { target musttail } } */
void f(void)
{
__attribute__((musttail)) return; /* { dg-error "cannot tail-call.*return value must be a call" } */
@@ -0,0 +1,108 @@
+/* { dg-do compile { target { musttail && { c || c++11 } } } } */
+
+int foo (int, void *);
+int bar (int, int *);
+struct S { int a, b, c; };
+struct T { int d; struct S e; };
+
+int
+baz (int x, void *y)
+{
+ [[gnu::musttail]] return bar (2, &x); /* { dg-warning "address of parameter 'x' passed to 'musttail' call argument" } */
+}
+
+int
+qux (int x, void *y)
+{
+ __label__ lab;
+ lab:;
+ if (*(int *) y == 1)
+ [[gnu::musttail]] return foo (1, &&lab); /* { dg-warning "address of label passed to 'musttail' call argument" } */
+ if (x == 1)
+ [[gnu::musttail]] return foo (3, 0);
+ else if (x == 2)
+ {
+ {
+ int a = 42;
+ bar (4, &a);
+ }
+ [[gnu::musttail]] return bar (5, 0);
+ }
+ else if (x == 3)
+ {
+ int a = 42;
+ bar (4, &a);
+ [[gnu::musttail]] return bar (6, 0);
+ }
+ else if (x == 4)
+ {
+ int a = 42;
+ [[gnu::musttail]] return bar (7, &a); /* { dg-warning "address of automatic variable 'a' passed to 'musttail' call argument" } */
+ }
+ else if (x == 5)
+ {
+ struct T b;
+ [[gnu::musttail]] return bar (8, &b.e.b); /* { dg-warning "address of automatic variable 'b' passed to 'musttail' call argument" } */
+ }
+ else if (x == 6)
+ {
+ struct T b;
+ bar (9, &b.e.a);
+ [[gnu::musttail]] return bar (10, 0);
+ }
+ else if (x == 7)
+ {
+ {
+ struct T b;
+ bar (9, &b.e.a);
+ }
+ [[gnu::musttail]] return bar (11, 0);
+ }
+ else if (x == 8)
+ {
+ {
+ int a = 42;
+ bar (4, &a);
+ }
+ [[gnu::musttail]] return foo (12, 0);
+ }
+ else if (x == 9)
+ {
+ int a = 42;
+ bar (4, &a);
+ [[gnu::musttail]] return foo (13, 0);
+ }
+ else if (x == 10)
+ {
+ int a = 42;
+ [[gnu::musttail]] return foo (14, &a); /* { dg-warning "address of automatic variable 'a' passed to 'musttail' call argument" } */
+ }
+ else if (x == 11)
+ {
+ struct T b;
+ [[gnu::musttail]] return foo (15, &b.e.b); /* { dg-warning "address of automatic variable 'b' passed to 'musttail' call argument" } */
+ }
+ else if (x == 12)
+ {
+ struct T b;
+ bar (9, &b.e.a);
+ [[gnu::musttail]] return foo (16, 0);
+ }
+ else if (x == 13)
+ {
+ {
+ struct T b;
+ bar (9, &b.e.a);
+ }
+ [[gnu::musttail]] return foo (17, 0);
+ }
+ return 0;
+}
+
+int
+corge (int x, void *y)
+{
+ if (*(int *) y == 1)
+ bar (18, &x);
+ [[gnu::musttail]] return bar (2, 0);
+}
@@ -0,0 +1,109 @@
+/* { dg-do compile { target { musttail && { c || c++11 } } } } */
+/* { dg-options "-O2 -Wmusttail-local-addr" } */
+
+int foo (int, void *);
+int bar (int, int *);
+struct S { int a, b, c; };
+struct T { int d; struct S e; };
+
+int
+baz (int x, void *y)
+{
+ [[gnu::musttail]] return bar (2, &x); /* { dg-warning "address of parameter 'x' passed to 'musttail' call argument" } */
+}
+
+int
+qux (int x, void *y)
+{
+ __label__ lab;
+ lab:;
+ if (*(int *) y == 1)
+ [[gnu::musttail]] return foo (1, &&lab); /* { dg-warning "address of label passed to 'musttail' call argument" } */
+ if (x == 1)
+ [[gnu::musttail]] return foo (3, 0);
+ else if (x == 2)
+ {
+ {
+ int a = 42;
+ bar (4, &a);
+ }
+ [[gnu::musttail]] return bar (5, 0);
+ }
+ else if (x == 3)
+ {
+ int a = 42;
+ bar (4, &a);
+ [[gnu::musttail]] return bar (6, 0);
+ }
+ else if (x == 4)
+ {
+ int a = 42;
+ [[gnu::musttail]] return bar (7, &a); /* { dg-warning "address of automatic variable 'a' passed to 'musttail' call argument" } */
+ }
+ else if (x == 5)
+ {
+ struct T b;
+ [[gnu::musttail]] return bar (8, &b.e.b); /* { dg-warning "address of automatic variable 'b' passed to 'musttail' call argument" } */
+ }
+ else if (x == 6)
+ {
+ struct T b;
+ bar (9, &b.e.a);
+ [[gnu::musttail]] return bar (10, 0);
+ }
+ else if (x == 7)
+ {
+ {
+ struct T b;
+ bar (9, &b.e.a);
+ }
+ [[gnu::musttail]] return bar (11, 0);
+ }
+ else if (x == 8)
+ {
+ {
+ int a = 42;
+ bar (4, &a);
+ }
+ [[gnu::musttail]] return foo (12, 0);
+ }
+ else if (x == 9)
+ {
+ int a = 42;
+ bar (4, &a);
+ [[gnu::musttail]] return foo (13, 0);
+ }
+ else if (x == 10)
+ {
+ int a = 42;
+ [[gnu::musttail]] return foo (14, &a); /* { dg-warning "address of automatic variable 'a' passed to 'musttail' call argument" } */
+ }
+ else if (x == 11)
+ {
+ struct T b;
+ [[gnu::musttail]] return foo (15, &b.e.b); /* { dg-warning "address of automatic variable 'b' passed to 'musttail' call argument" } */
+ }
+ else if (x == 12)
+ {
+ struct T b;
+ bar (9, &b.e.a);
+ [[gnu::musttail]] return foo (16, 0);
+ }
+ else if (x == 13)
+ {
+ {
+ struct T b;
+ bar (9, &b.e.a);
+ }
+ [[gnu::musttail]] return foo (17, 0);
+ }
+ return 0;
+}
+
+int
+corge (int x, void *y)
+{
+ if (*(int *) y == 1)
+ bar (18, &x);
+ [[gnu::musttail]] return bar (2, 0);
+}
@@ -0,0 +1,109 @@
+/* { dg-do compile { target { musttail && { c || c++11 } } } } */
+/* { dg-options "-Wextra" } */
+
+int foo (int, void *);
+int bar (int, int *);
+struct S { int a, b, c; };
+struct T { int d; struct S e; };
+
+int
+baz (int x, void *y)
+{
+ [[gnu::musttail]] return bar (2, &x); /* { dg-warning "address of parameter 'x' passed to 'musttail' call argument" } */
+}
+
+int
+qux (int x, void *y)
+{
+ __label__ lab;
+ lab:;
+ if (*(int *) y == 1)
+ [[gnu::musttail]] return foo (1, &&lab); /* { dg-warning "address of label passed to 'musttail' call argument" } */
+ if (x == 1)
+ [[gnu::musttail]] return foo (3, 0);
+ else if (x == 2)
+ {
+ {
+ int a = 42;
+ bar (4, &a);
+ }
+ [[gnu::musttail]] return bar (5, 0);
+ }
+ else if (x == 3)
+ {
+ int a = 42;
+ bar (4, &a);
+ [[gnu::musttail]] return bar (6, 0); /* { dg-warning "address of automatic variable 'a' can escape to 'musttail' call" } */
+ }
+ else if (x == 4)
+ {
+ int a = 42;
+ [[gnu::musttail]] return bar (7, &a); /* { dg-warning "address of automatic variable 'a' passed to 'musttail' call argument" } */
+ }
+ else if (x == 5)
+ {
+ struct T b;
+ [[gnu::musttail]] return bar (8, &b.e.b); /* { dg-warning "address of automatic variable 'b' passed to 'musttail' call argument" } */
+ }
+ else if (x == 6)
+ {
+ struct T b;
+ bar (9, &b.e.a);
+ [[gnu::musttail]] return bar (10, 0); /* { dg-warning "address of automatic variable 'b' can escape to 'musttail' call" } */
+ }
+ else if (x == 7)
+ {
+ {
+ struct T b;
+ bar (9, &b.e.a);
+ }
+ [[gnu::musttail]] return bar (11, 0);
+ }
+ else if (x == 8)
+ {
+ {
+ int a = 42;
+ bar (4, &a);
+ }
+ [[gnu::musttail]] return foo (12, 0);
+ }
+ else if (x == 9)
+ {
+ int a = 42;
+ bar (4, &a);
+ [[gnu::musttail]] return foo (13, 0); /* { dg-warning "address of automatic variable 'a' can escape to 'musttail' call" } */
+ }
+ else if (x == 10)
+ {
+ int a = 42;
+ [[gnu::musttail]] return foo (14, &a); /* { dg-warning "address of automatic variable 'a' passed to 'musttail' call argument" } */
+ }
+ else if (x == 11)
+ {
+ struct T b;
+ [[gnu::musttail]] return foo (15, &b.e.b); /* { dg-warning "address of automatic variable 'b' passed to 'musttail' call argument" } */
+ }
+ else if (x == 12)
+ {
+ struct T b;
+ bar (9, &b.e.a);
+ [[gnu::musttail]] return foo (16, 0); /* { dg-warning "address of automatic variable 'b' can escape to 'musttail' call" } */
+ }
+ else if (x == 13)
+ {
+ {
+ struct T b;
+ bar (9, &b.e.a);
+ }
+ [[gnu::musttail]] return foo (17, 0);
+ }
+ return 0;
+}
+
+int
+corge (int x, void *y)
+{
+ if (*(int *) y == 1)
+ bar (18, &x);
+ [[gnu::musttail]] return bar (2, 0); /* { dg-warning "address of parameter 'x' can escape to 'musttail' call" } */
+}
@@ -0,0 +1,109 @@
+/* { dg-do compile { target { musttail && { c || c++11 } } } } */
+/* { dg-options "-O2 -Wmaybe-musttail-local-addr" } */
+
+int foo (int, void *);
+int bar (int, int *);
+struct S { int a, b, c; };
+struct T { int d; struct S e; };
+
+int
+baz (int x, void *y)
+{
+ [[gnu::musttail]] return bar (2, &x); /* { dg-warning "address of parameter 'x' passed to 'musttail' call argument" } */
+}
+
+int
+qux (int x, void *y)
+{
+ __label__ lab;
+ lab:;
+ if (*(int *) y == 1)
+ [[gnu::musttail]] return foo (1, &&lab); /* { dg-warning "address of label passed to 'musttail' call argument" } */
+ if (x == 1)
+ [[gnu::musttail]] return foo (3, 0);
+ else if (x == 2)
+ {
+ {
+ int a = 42;
+ bar (4, &a);
+ }
+ [[gnu::musttail]] return bar (5, 0);
+ }
+ else if (x == 3)
+ {
+ int a = 42;
+ bar (4, &a);
+ [[gnu::musttail]] return bar (6, 0); /* { dg-warning "address of automatic variable 'a' can escape to 'musttail' call" } */
+ }
+ else if (x == 4)
+ {
+ int a = 42;
+ [[gnu::musttail]] return bar (7, &a); /* { dg-warning "address of automatic variable 'a' passed to 'musttail' call argument" } */
+ }
+ else if (x == 5)
+ {
+ struct T b;
+ [[gnu::musttail]] return bar (8, &b.e.b); /* { dg-warning "address of automatic variable 'b' passed to 'musttail' call argument" } */
+ }
+ else if (x == 6)
+ {
+ struct T b;
+ bar (9, &b.e.a);
+ [[gnu::musttail]] return bar (10, 0); /* { dg-warning "address of automatic variable 'b' can escape to 'musttail' call" } */
+ }
+ else if (x == 7)
+ {
+ {
+ struct T b;
+ bar (9, &b.e.a);
+ }
+ [[gnu::musttail]] return bar (11, 0);
+ }
+ else if (x == 8)
+ {
+ {
+ int a = 42;
+ bar (4, &a);
+ }
+ [[gnu::musttail]] return foo (12, 0);
+ }
+ else if (x == 9)
+ {
+ int a = 42;
+ bar (4, &a);
+ [[gnu::musttail]] return foo (13, 0); /* { dg-warning "address of automatic variable 'a' can escape to 'musttail' call" } */
+ }
+ else if (x == 10)
+ {
+ int a = 42;
+ [[gnu::musttail]] return foo (14, &a); /* { dg-warning "address of automatic variable 'a' passed to 'musttail' call argument" } */
+ }
+ else if (x == 11)
+ {
+ struct T b;
+ [[gnu::musttail]] return foo (15, &b.e.b); /* { dg-warning "address of automatic variable 'b' passed to 'musttail' call argument" } */
+ }
+ else if (x == 12)
+ {
+ struct T b;
+ bar (9, &b.e.a);
+ [[gnu::musttail]] return foo (16, 0); /* { dg-warning "address of automatic variable 'b' can escape to 'musttail' call" } */
+ }
+ else if (x == 13)
+ {
+ {
+ struct T b;
+ bar (9, &b.e.a);
+ }
+ [[gnu::musttail]] return foo (17, 0);
+ }
+ return 0;
+}
+
+int
+corge (int x, void *y)
+{
+ if (*(int *) y == 1)
+ bar (18, &x);
+ [[gnu::musttail]] return bar (2, 0); /* { dg-warning "address of parameter 'x' can escape to 'musttail' call" } */
+}
@@ -0,0 +1,38 @@
+// PR ipa/119376
+// { dg-do compile { target { musttail && c++11 } } }
+// { dg-options "-Wmaybe-musttail-local-addr" }
+
+int foo (int &);
+int bar (int &&);
+int corge (int *);
+
+int
+baz (int &x)
+{
+ if (x == 1)
+ [[gnu::musttail]] return foo (x);
+ if (x == 2)
+ {
+ int a = 42;
+ [[gnu::musttail]] return foo (a); // { dg-warning "address of automatic variable 'a' passed to 'musttail' call argument" }
+ }
+ if (x == 3)
+ {
+ int a = 42;
+ foo (a);
+ [[gnu::musttail]] return foo (x); // { dg-warning "address of automatic variable 'a' can escape to 'musttail' call" }
+ }
+ return 0;
+}
+
+int
+qux (int &&x)
+{
+ [[gnu::musttail]] return bar (x + 1); // { dg-warning "address of local variable passed to 'musttail' call argument" }
+}
+
+int
+freddy (int x)
+{
+ [[gnu::musttail]] return foo (x); // { dg-warning "address of parameter 'x' passed to 'musttail' call argument" }
+}
@@ -0,0 +1,38 @@
+// PR ipa/119376
+// { dg-do compile { target { musttail && c++11 } } }
+// { dg-options "-Wextra" }
+
+int foo (int &);
+int bar (int &&);
+int corge (int *);
+
+int
+baz (int &x)
+{
+ if (x == 1)
+ [[clang::musttail]] return foo (x);
+ if (x == 2)
+ {
+ int a = 42;
+ [[clang::musttail]] return foo (a); // { dg-warning "address of automatic variable 'a' passed to 'musttail' call argument" }
+ }
+ if (x == 3)
+ {
+ int a = 42;
+ foo (a);
+ [[clang::musttail]] return foo (x); // { dg-warning "address of automatic variable 'a' can escape to 'musttail' call" }
+ }
+ return 0;
+}
+
+int
+qux (int &&x)
+{
+ [[clang::musttail]] return bar (x + 1); // { dg-warning "address of local variable passed to 'musttail' call argument" }
+}
+
+int
+freddy (int x)
+{
+ [[clang::musttail]] return foo (x); // { dg-warning "address of parameter 'x' passed to 'musttail' call argument" }
+}
@@ -0,0 +1,37 @@
+// PR ipa/119376
+// { dg-do compile { target { musttail && c++11 } } }
+
+int foo (int &);
+int bar (int &&);
+int corge (int *);
+
+int
+baz (int &x)
+{
+ if (x == 1)
+ [[gnu::musttail]] return foo (x);
+ if (x == 2)
+ {
+ int a = 42;
+ [[gnu::musttail]] return foo (a); // { dg-warning "address of automatic variable 'a' passed to 'musttail' call argument" }
+ }
+ if (x == 3)
+ {
+ int a = 42;
+ foo (a);
+ [[gnu::musttail]] return foo (x);
+ }
+ return 0;
+}
+
+int
+qux (int &&x)
+{
+ [[gnu::musttail]] return bar (x + 1); // { dg-warning "address of local variable passed to 'musttail' call argument" }
+}
+
+int
+freddy (int x)
+{
+ [[gnu::musttail]] return foo (x); // { dg-warning "address of parameter 'x' passed to 'musttail' call argument" }
+}