A 2017 change that propagated call location to GIMPLE statements
had the unexpected (though not incorrect) effect of setting
the location on calls to __builtin_alloca.  When such calls are
the result of the expansion of the alloca macro defined in
a system header like <alloca.h>, the change prevents -Walloca and -Walloca-larger-than
warnings from being issued unless -Wsystem-headers is also used,
effectively defeating the point of the first two warnings in most
code.

The attached patch changes -Walloca to use the location of the point
of the macro expansion rather than that of its definition, restoring
the intended behavior.

In addition, to make the warnings (mainly -Wvla) in inlined code
easier to debug, the patch also arranges for the warnings to include
their inlining context.

Tested on x86_64-linux.

Martin
PR middle-end/94004 - missing -Walloca on calls to alloca due to -Wno-system-headers

gcc/testsuite/ChangeLog:

	PR middle-end/94004
	* gcc.dg/Walloca-larger-than-3.c: New test.
	* gcc.dg/Wvla-larger-than-4.c: New test.

gcc/ChangeLog:

	PR middle-end/94004
	* gimple-ssa-warn-alloca.c (pass_walloca::execute): Issue warnings
	even for alloca calls resulting from system macro expansion.
	Include inlining context in all warnings.

diff --git a/gcc/gimple-ssa-warn-alloca.c b/gcc/gimple-ssa-warn-alloca.c
index dfe40c9c02a..9e80e5dbbd9 100644
--- a/gcc/gimple-ssa-warn-alloca.c
+++ b/gcc/gimple-ssa-warn-alloca.c
@@ -510,11 +510,12 @@ pass_walloca::execute (function *fun)
 	   gsi_next (&si))
 	{
 	  gimple *stmt = gsi_stmt (si);
-	  location_t loc = gimple_location (stmt);
-
 	  if (!gimple_alloca_call_p (stmt))
 	    continue;
 
+	  location_t loc = gimple_nonartificial_location (stmt);
+	  loc = expansion_point_location_if_in_system_header (loc);
+
 	  const bool is_vla
 	    = gimple_call_alloca_for_var_p (as_a <gcall *> (stmt));
 
@@ -528,7 +529,7 @@ pass_walloca::execute (function *fun)
 	    }
 	  else if (warn_alloca)
 	    {
-	      warning_at (loc, OPT_Walloca, "use of %<alloca%>");
+	      warning_at (loc, OPT_Walloca, "%Guse of %<alloca%>", stmt);
 	      continue;
 	    }
 	  else if (warn_alloca_limit < 0)
@@ -564,10 +565,12 @@ pass_walloca::execute (function *fun)
 	      {
 		auto_diagnostic_group d;
 		if (warning_at (loc, wcode,
-				is_vla ? G_("argument to variable-length "
-					    "array may be too large")
-				: G_("argument to %<alloca%> may be too "
-				     "large"))
+				(is_vla
+				 ? G_("%Gargument to variable-length "
+				      "array may be too large")
+				 : G_("%Gargument to %<alloca%> may be too "
+				      "large")),
+				stmt)
 		    && t.limit != 0)
 		  {
 		    print_decu (t.limit, buff);
@@ -582,47 +585,57 @@ pass_walloca::execute (function *fun)
 	      {
 		auto_diagnostic_group d;
 		if (warning_at (loc, wcode,
-				is_vla ? G_("argument to variable-length"
-					    " array is too large")
-				: G_("argument to %<alloca%> is too large"))
+				(is_vla
+				 ? G_("%Gargument to variable-length"
+				      " array is too large")
+				 : G_("%Gargument to %<alloca%> is too large")),
+				stmt)
 		    && t.limit != 0)
 		  {
 		    print_decu (t.limit, buff);
 		    inform (loc, "limit is %wu bytes, but argument is %s",
-			      is_vla ? warn_vla_limit : adjusted_alloca_limit,
-			      buff);
+			    is_vla ? warn_vla_limit : adjusted_alloca_limit,
+			    buff);
 		  }
 	      }
 	      break;
 	    case ALLOCA_BOUND_UNKNOWN:
 	      warning_at (loc, wcode,
-			  is_vla ? G_("variable-length array bound is unknown")
-			  : G_("%<alloca%> bound is unknown"));
+			  (is_vla
+			   ? G_("%Gvariable-length array bound is unknown")
+			   : G_("%G%<alloca%> bound is unknown")),
+			  stmt);
 	      break;
 	    case ALLOCA_UNBOUNDED:
 	      warning_at (loc, wcode,
-			  is_vla ? G_("unbounded use of variable-length array")
-			  : G_("unbounded use of %<alloca%>"));
+			  (is_vla
+			   ? G_("%Gunbounded use of variable-length array")
+			   : G_("%Gunbounded use of %<alloca%>")),
+			  stmt);
 	      break;
 	    case ALLOCA_IN_LOOP:
 	      gcc_assert (!is_vla);
-	      warning_at (loc, wcode, "use of %<alloca%> within a loop");
+	      warning_at (loc, wcode,
+			  "%Guse of %<alloca%> within a loop", stmt);
 	      break;
 	    case ALLOCA_CAST_FROM_SIGNED:
 	      gcc_assert (invalid_casted_type != NULL_TREE);
 	      warning_at (loc, wcode,
-			  is_vla ? G_("argument to variable-length array "
-				      "may be too large due to "
-				      "conversion from %qT to %qT")
-			  : G_("argument to %<alloca%> may be too large "
-			       "due to conversion from %qT to %qT"),
-			  invalid_casted_type, size_type_node);
+			  (is_vla
+			   ? G_("%Gargument to variable-length array "
+				"may be too large due to "
+				"conversion from %qT to %qT")
+			   : G_("%Gargument to %<alloca%> may be too large "
+				"due to conversion from %qT to %qT")),
+			  stmt, invalid_casted_type, size_type_node);
 	      break;
 	    case ALLOCA_ARG_IS_ZERO:
 	      warning_at (loc, wcode,
-			  is_vla ? G_("argument to variable-length array "
-				      "is zero")
-			  : G_("argument to %<alloca%> is zero"));
+			  (is_vla
+			   ? G_("%Gargument to variable-length array "
+				"is zero")
+			   : G_("%Gargument to %<alloca%> is zero")),
+			  stmt);
 	      break;
 	    default:
 	      gcc_unreachable ();
diff --git a/gcc/testsuite/gcc.dg/Walloca-larger-than-3.c b/gcc/testsuite/gcc.dg/Walloca-larger-than-3.c
new file mode 100644
index 00000000000..c298d6c4c75
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Walloca-larger-than-3.c
@@ -0,0 +1,48 @@
+/* PR middle-end/94004 - missing -Walloca on calls to alloca due
+   to -Wno-system-headers
+   { dg-do compile }
+   { dg-options "-O2 -Wall -Walloca-larger-than=8 -ftrack-macro-expansion=0" }
+   { dg-require-effective-target alloca } */
+
+#if __has_include (<alloca.h>)
+#  include <alloca.h>
+#endif
+
+#ifndef alloca
+// Simulate a definition in a system header.
+#  13 "/usr/include/alloca.h"
+#  define alloca(n) __builtin_alloca (n)
+#  15 "Walloca-larger-than-3.c"
+#endif
+
+
+void sink (void*, ...);
+
+void call_builtin_alloca (int n)
+{
+  if (n < 9)
+    n = 9;
+  void *p = __builtin_alloca (n);   // { dg-warning "\\\[-Walloca-larger-than" }
+  sink (p, 0);
+}
+
+void call_alloca_sys_hdr (int n)
+{
+  if (n < 9)
+    n = 9;
+  void *p = alloca (n);             // { dg-warning "\\\[-Walloca-larger-than" }
+  sink (p, 1);
+}
+
+static inline void inline_call_alloca (int n)
+{
+  if (n > 9)
+    n = 9;
+  void *p = alloca (n);             // { dg-warning "\\\[-Walloca-larger-than" }
+  sink (p, 2);
+}
+
+void make_inlined_call (void)
+{
+  inline_call_alloca (10);
+}
diff --git a/gcc/testsuite/gcc.dg/Wvla-larger-than-4.c b/gcc/testsuite/gcc.dg/Wvla-larger-than-4.c
new file mode 100644
index 00000000000..de99afbe56e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wvla-larger-than-4.c
@@ -0,0 +1,30 @@
+/* PR middle-end/94004 - missing -Walloca on calls to alloca due
+   to -Wno-system-headers
+   { dg-do compile }
+   { dg-options "-O2 -Wall -Wvla-larger-than=31 -ftrack-macro-expansion=0" }
+   { dg-require-effective-target alloca } */
+
+void sink (void*, ...);
+
+static inline void inline_use_vla (unsigned n)
+{
+  if (n > 32)
+    n = 32;
+  char a[n];                  // { dg-warning "\\\[-Wvla-larger-than" }
+  sink (a, 2);
+}
+
+static inline void use_inlined_vla (unsigned n)
+{
+  inline_use_vla (n);         // this call is okay
+  inline_use_vla (n + 1);     // this one is not
+}
+
+void call_inline (void)
+{
+  use_inlined_vla (31);
+}
+
+/* Verify that the inlining context is included and that it points
+   to the correct line number in the inlined function:
+   { dg-message "function 'inline_use_vla'..*inlined from 'call_inline' .*:20:" "" { target *-*-* } 0 }  */

Reply via email to