This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Support printing inlining call stack in diagnostic messages (take 2)


On Mon, Sep 10, 2007 at 11:56:35AM -0400, Daniel Jacobowitz wrote:
> On Mon, Sep 10, 2007 at 07:21:48AM -0400, Jakub Jelinek wrote:
> > LC_ALL=C ./xgcc -B ./ -O2 builtin-stringop-chk-3.c -S
> > In function 'foo',
> >     inlined from 'bar' at builtin-stringop-chk-1.h:6,
> >     inlined from 'baz' at builtin-stringop-chk-3.c:5:
> > builtin-stringop-chk-2.h:5: warning: call to __builtin___memcpy_chk will always overflow destination buffer
> 
> I don't think this is a good idea.  There's more tools than just
> dejagnu that parse GCC output (emacs, Eclipse, ...).  Can't these
> be more note:'s or warning:'s?  Analogy with the "included
> from here" message.

As Mark is on the boat with you on this, I have implemented the
note approach.

For some reason g++.dg/ testsuite harness doesn't grok dg-message
(while gcc.dg/ does), but at least for now dg-warning instead
works as well even when it is a note.

On the source I posted yesterday with this patch we now print:
LC_ALL=C ./xgcc -B ./ -O2 -S /tmp/q3.c; echo; LC_ALL=C ./g++ -B ./ -O2 -S /tmp/q3.c
bar.h: In function 'foo':
bar.h:5: warning: call to __builtin___memcpy_chk will always overflow destination buffer
foo.h:6: note: inlined from 'bar'
foo.c:5: note: inlined from 'baz'

bar.h: In function 'int foo()':
bar.h:5: warning: call to void* __builtin___memcpy_chk(void*, const void*, long unsigned int, long unsigned int) will always overflow destination buffer
foo.h:6: note: inlined from 'int bar()'
foo.c:5: note: inlined from 'int baz()'

Tested on x86_64-linux, ok for trunk?

2007-09-11  Jakub Jelinek  <jakub@redhat.com>

	* Makefile.in (OBJS-common): Add tree-error.o.
	(tree-error.o): Add dependencies.
	* tree-error.c: New file.
	* toplev.h (warning_for_stmt, error_for_stmt): New prototypes.
	* expr.c (expand_expr_real_1): Use error_for_stmt.
	* builtins.c (expand_builtin, expand_builtin_object_size,
	expand_builtin_memory_chk, maybe_emit_chk_warning,
	maybe_emit_sprintf_chk_warning): Use error_for_stmt or
	warning_for_stmt.

	* gcc.dg/va-arg-pack-1.c: Add dg-message where appropriate.
	* g++.dg/ext/va-arg-pack-2.C: Likewise.

--- gcc/toplev.h.jj	2007-09-04 23:09:30.000000000 +0200
+++ gcc/toplev.h	2007-09-11 13:29:17.000000000 +0200
@@ -66,6 +66,10 @@ extern void sorry (const char *, ...) AT
 extern void inform (const char *, ...) ATTRIBUTE_GCC_DIAG(1,2);
 extern void verbatim (const char *, ...) ATTRIBUTE_GCC_DIAG(1,2);
 
+/* Pass one of the OPT_W* from options.h as the first parameter.  */
+extern void warning_for_stmt (int, tree, const char *, ...) ATTRIBUTE_GCC_DIAG(3,4);
+extern void error_for_stmt (tree, const char *, ...) ATTRIBUTE_GCC_DIAG(2,3);
+
 extern void rest_of_decl_compilation (tree, int, int);
 extern void rest_of_type_compilation (tree, int);
 extern void tree_rest_of_compilation (tree);
--- gcc/expr.c.jj	2007-09-11 12:43:28.000000000 +0200
+++ gcc/expr.c	2007-09-11 13:36:20.000000000 +0200
@@ -7966,7 +7966,7 @@ expand_expr_real_1 (tree exp, rtx target
       /* All valid uses of __builtin_va_arg_pack () are removed during
 	 inlining.  */
       if (CALL_EXPR_VA_ARG_PACK (exp))
-	error ("invalid use of %<__builtin_va_arg_pack ()%>");
+	error_for_stmt (exp, "invalid use of %<__builtin_va_arg_pack ()%>");
       /* Check for a built-in function.  */
       if (TREE_CODE (CALL_EXPR_FN (exp)) == ADDR_EXPR
 	  && (TREE_CODE (TREE_OPERAND (CALL_EXPR_FN (exp), 0))
--- gcc/builtins.c.jj	2007-09-11 12:43:28.000000000 +0200
+++ gcc/builtins.c	2007-09-11 13:52:29.000000000 +0200
@@ -6273,7 +6273,7 @@ expand_builtin (tree exp, rtx target, rt
     case BUILT_IN_VA_ARG_PACK:
       /* All valid uses of __builtin_va_arg_pack () are removed during
 	 inlining.  */
-      error ("invalid use of %<__builtin_va_arg_pack ()%>");
+      error_for_stmt (exp, "invalid use of %<__builtin_va_arg_pack ()%>");
       return const0_rtx;
 
       /* Return the address of the first anonymous stack arg.  */
@@ -11460,12 +11460,12 @@ expand_builtin_object_size (tree exp)
   tree ost;
   int object_size_type;
   tree fndecl = get_callee_fndecl (exp);
-  location_t locus = EXPR_LOCATION (exp);
 
   if (!validate_arglist (exp, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
     {
-      error ("%Hfirst argument of %D must be a pointer, second integer constant",
-	     &locus, fndecl);
+      error_for_stmt (exp,
+		      "first argument of %D must be a pointer, second integer constant",
+		      fndecl);
       expand_builtin_trap ();
       return const0_rtx;
     }
@@ -11477,8 +11477,9 @@ expand_builtin_object_size (tree exp)
       || tree_int_cst_sgn (ost) < 0
       || compare_tree_int (ost, 3) > 0)
     {
-      error ("%Hlast argument of %D is not integer constant between 0 and 3",
-	     &locus, fndecl);
+      error_for_stmt (exp,
+		      "last argument of %D is not integer constant between 0 and 3",
+		      fndecl);
       expand_builtin_trap ();
       return const0_rtx;
     }
@@ -11521,9 +11522,9 @@ expand_builtin_memory_chk (tree exp, rtx
 
       if (! integer_all_onesp (size) && tree_int_cst_lt (size, len))
 	{
-	  location_t locus = EXPR_LOCATION (exp);
-	  warning (0, "%Hcall to %D will always overflow destination buffer",
-		   &locus, get_callee_fndecl (exp));
+	  warning_for_stmt (0, exp,
+			    "call to %D will always overflow destination buffer",
+			    get_callee_fndecl (exp));
 	  return NULL_RTX;
 	}
 
@@ -11616,7 +11617,6 @@ maybe_emit_chk_warning (tree exp, enum b
 {
   int is_strlen = 0;
   tree len, size;
-  location_t locus;
 
   switch (fcode)
     {
@@ -11663,9 +11663,9 @@ maybe_emit_chk_warning (tree exp, enum b
       src = c_strlen (src, 1);
       if (! src || ! host_integerp (src, 1))
 	{
-	  locus = EXPR_LOCATION (exp);
-	  warning (0, "%Hcall to %D might overflow destination buffer",
-		   &locus, get_callee_fndecl (exp));
+	  warning_for_stmt (0, exp,
+			    "call to %D might overflow destination buffer",
+			    get_callee_fndecl (exp));
 	  return;
 	}
       else if (tree_int_cst_lt (src, size))
@@ -11674,9 +11674,9 @@ maybe_emit_chk_warning (tree exp, enum b
   else if (! host_integerp (len, 1) || ! tree_int_cst_lt (size, len))
     return;
 
-  locus = EXPR_LOCATION (exp);
-  warning (0, "%Hcall to %D will always overflow destination buffer",
-	   &locus, get_callee_fndecl (exp));
+  warning_for_stmt (0, exp,
+		    "call to %D will always overflow destination buffer",
+		    get_callee_fndecl (exp));
 }
 
 /* Emit warning if a buffer overflow is detected at compile time
@@ -11733,11 +11733,9 @@ maybe_emit_sprintf_chk_warning (tree exp
     return;
 
   if (! tree_int_cst_lt (len, size))
-    {
-      location_t locus = EXPR_LOCATION (exp);
-      warning (0, "%Hcall to %D will always overflow destination buffer",
-	       &locus, get_callee_fndecl (exp));
-    }
+    warning_for_stmt (0, exp,
+		      "call to %D will always overflow destination buffer",
+		      get_callee_fndecl (exp));
 }
 
 /* Fold a call to __builtin_object_size with arguments PTR and OST,
--- gcc/Makefile.in.jj	2007-09-11 12:43:43.000000000 +0200
+++ gcc/Makefile.in	2007-09-11 13:43:29.000000000 +0200
@@ -1143,6 +1143,7 @@ OBJS-common = \
 	tree-dfa.o \
 	tree-dump.o \
 	tree-eh.o \
+	tree-error.o \
 	tree-gimple.o \
 	tree-if-conv.o \
 	tree-into-ssa.o \
@@ -2308,6 +2309,8 @@ targhooks.o : targhooks.c $(CONFIG_H) $(
    $(EXPR_H) $(TM_H) $(RTL_H) $(TM_P_H) $(FUNCTION_H) output.h toplev.h \
    $(MACHMODE_H) $(TARGET_DEF_H) $(TARGET_H) $(GGC_H) gt-targhooks.h \
    $(OPTABS_H)
+tree-error.o: tree-error.c $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
+   input.h toplev.h intl.h langhooks.h $(DIAGNOSTIC_H) $(CONFIG_H)
 
 toplev.o : toplev.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
    version.h $(RTL_H) $(FUNCTION_H) $(FLAGS_H) xcoffout.h input.h \
--- gcc/tree-error.c.jj	2007-09-11 12:52:08.000000000 +0200
+++ gcc/tree-error.c	2007-09-11 13:54:07.000000000 +0200
@@ -0,0 +1,165 @@
+/* TREE specific diagnostic subroutines for GCC
+   Copyright (C) 2007 Free Software Foundation, Inc.
+   Contributed by Jakub Jelinek <jakub@redhat.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "input.h"
+#include "toplev.h"
+#include "intl.h"
+#include "langhooks.h"
+#include "diagnostic.h"
+
+static void diagnostic_for_stmt (int, tree, const char *, va_list *,
+				 diagnostic_t) ATTRIBUTE_GCC_DIAG (3,0);
+static void inlined_from_here_note (int, location_t, const char *gmsgid,
+				    ...) ATTRIBUTE_GCC_DIAG (3,4);
+
+/* Helper function for diagnostic_for_stmt, as diagnostic_set_info
+   needs an address of va_list object.  */
+static void
+inlined_from_here_note (int option_index, location_t locus,
+			const char *gmsgid, ...)
+{
+  diagnostic_info diagnostic;
+  va_list ap;
+
+  va_start (ap, gmsgid);
+  diagnostic_set_info (&diagnostic, gmsgid, &ap, locus, DK_NOTE);
+  diagnostic.option_index = option_index;
+  report_diagnostic (&diagnostic);
+  va_end (ap);
+}
+
+/* Report a diagnostic MSG (an error or a warning) at the line number
+   of the statement STMT.  */
+static void
+diagnostic_for_stmt (int option_index, tree stmt, const char *msg,
+		     va_list *args_ptr, diagnostic_t kind)
+{
+  diagnostic_info diagnostic;
+  tree block = TREE_BLOCK (stmt);
+  tree fndecl, saved_current_function_decl, next_block;
+
+  /* If STMT comes from some inline function, for the duration
+     of the diagnostics change current_function_decl to the
+     inline function instead of the function it has been inlined
+     into.  */
+  saved_current_function_decl = current_function_decl;
+  fndecl = current_function_decl;
+  while (block
+	 && TREE_CODE (block) == BLOCK
+	 && BLOCK_ABSTRACT_ORIGIN (block))
+    {
+      tree ao = BLOCK_ABSTRACT_ORIGIN (block);
+
+      while (TREE_CODE (ao) == BLOCK && BLOCK_ABSTRACT_ORIGIN (ao))
+	ao = BLOCK_ABSTRACT_ORIGIN (ao);
+      if (TREE_CODE (ao) == FUNCTION_DECL)
+	{
+	  fndecl = ao;
+	  break;
+	}
+      block = BLOCK_SUPERCONTEXT (block);
+    }
+  current_function_decl = fndecl;
+
+  diagnostic_set_info (&diagnostic, msg, args_ptr,
+		       EXPR_LOCATION (stmt), kind);
+  diagnostic.option_index = option_index;
+  report_diagnostic (&diagnostic);
+
+  if (fndecl != saved_current_function_decl)
+    for (; block; block = next_block)
+      {
+	location_t locus = BLOCK_SOURCE_LOCATION (block);
+
+	fndecl = NULL_TREE;
+	block = BLOCK_SUPERCONTEXT (block);
+	while (block && TREE_CODE (block) == BLOCK
+	       && BLOCK_ABSTRACT_ORIGIN (block))
+	  {
+	    tree ao = BLOCK_ABSTRACT_ORIGIN (block);
+
+	    while (TREE_CODE (ao) == BLOCK
+		   && BLOCK_ABSTRACT_ORIGIN (ao))
+	      ao = BLOCK_ABSTRACT_ORIGIN (ao);
+
+	    if (TREE_CODE (ao) == FUNCTION_DECL)
+	      {
+		fndecl = ao;
+		break;
+	      }
+	    else if (TREE_CODE (ao) != BLOCK)
+	      break;
+
+	    block = BLOCK_SUPERCONTEXT (block);
+	  }
+
+	if (fndecl)
+	  next_block = block;
+	else
+	  {
+	    while (block && TREE_CODE (block) == BLOCK)
+	      block = BLOCK_SUPERCONTEXT (block);
+
+	    if (TREE_CODE (block) == FUNCTION_DECL)
+	      fndecl = block;
+	    next_block = NULL;
+	  }
+
+	if (fndecl)
+	  inlined_from_here_note (option_index, locus, "inlined from %qs",
+				  lang_hooks.decl_printable_name (fndecl, 2));
+      }
+  current_function_decl = fndecl;
+}
+
+/* Report an error GMSGID at the line number of the statement STMT.
+   If STMT comes from an inline function, report it inside of the
+   inline function rather than with the containing function and
+   add note messages containing virtual call stack of the inline
+   function.  */
+void
+error_for_stmt (tree stmt, const char *gmsgid, ...)
+{
+  va_list ap;
+
+  va_start (ap, gmsgid);
+  diagnostic_for_stmt (0, stmt, gmsgid, &ap, DK_ERROR);
+  va_end (ap);
+}
+
+/* Report a warning GMSGID at the line number of the statement STMT.
+   If STMT comes from an inline function, report it inside of the
+   inline function rather than with the containing function and
+   add note messages containing virtual call stack of the inline
+   function.  */
+void
+warning_for_stmt (int option_index, tree stmt, const char *gmsgid, ...)
+{
+  va_list ap;
+
+  va_start (ap, gmsgid);
+  diagnostic_for_stmt (option_index, stmt, gmsgid, &ap, DK_WARNING);
+  va_end (ap);
+}
--- gcc/testsuite/gcc.dg/va-arg-pack-1.c.jj	2007-09-05 21:41:11.000000000 +0200
+++ gcc/testsuite/gcc.dg/va-arg-pack-1.c	2007-09-11 13:58:06.000000000 +0200
@@ -43,10 +43,10 @@ f6 (int y, ...)
 int
 test (void)
 {
-  int a = f2 (5, "a", 6);
+  int a = f2 (5, "a", 6);				/* { dg-message "inlined from" } */
   a += f3 (6, "ab", 17LL);
-  a += f4 (7, 1, 2, 3);
-  a += f5 (8, 7L);
-  a += f6 (9);
+  a += f4 (7, 1, 2, 3);					/* { dg-message "inlined from" } */
+  a += f5 (8, 7L);					/* { dg-message "inlined from" } */
+  a += f6 (9);						/* { dg-message "inlined from" } */
   return a;
 }
--- gcc/testsuite/g++.dg/ext/va-arg-pack-2.C.jj	2007-09-11 12:43:31.000000000 +0200
+++ gcc/testsuite/g++.dg/ext/va-arg-pack-2.C	2007-09-11 13:59:17.000000000 +0200
@@ -7,7 +7,7 @@ int baz (int, const char *, long int);
 extern inline __attribute__((always_inline)) int
 f2 (int y, ...)
 {
-  return bar (y, "", __builtin_va_arg_pack ());		/* { dg-error "invalid use of" } */
+  return bar (y, "", __builtin_va_arg_pack ());		// { dg-error "invalid use of" }
 }
 
 extern inline __attribute__((always_inline)) int
@@ -19,28 +19,28 @@ f3 (int y, ...)
 extern inline __attribute__((always_inline)) int
 f4 (int y, ...)
 {
-  return bar (y, "", 4, __builtin_va_arg_pack (), 6);	/* { dg-error "invalid use of" } */
+  return bar (y, "", 4, __builtin_va_arg_pack (), 6);	// { dg-error "invalid use of" }
 }
 
 extern inline __attribute__((always_inline)) int
 f5 (int y, ...)
 {
-  return baz (y, "", __builtin_va_arg_pack ());		/* { dg-error "invalid use of" } */
+  return baz (y, "", __builtin_va_arg_pack ());		// { dg-error "invalid use of" }
 }
 
 extern inline __attribute__((always_inline)) int
 f6 (int y, ...)
 {
-  return __builtin_va_arg_pack ();			/* { dg-error "invalid use of" } */
+  return __builtin_va_arg_pack ();			// { dg-error "invalid use of" }
 }
 
 int
 test (void)
 {
-  int a = f2 (5, "a", 6);
+  int a = f2 (5, "a", 6);				// { dg-warning "inlined from" }
   a += f3 (6, "ab", 17LL);
-  a += f4 (7, 1, 2, 3);
-  a += f5 (8, 7L);
-  a += f6 (9);
+  a += f4 (7, 1, 2, 3);					// { dg-warning "inlined from" }
+  a += f5 (8, 7L);					// { dg-warning "inlined from" }
+  a += f6 (9);						// { dg-warning "inlined from" }
   return a;
 }


	Jakub


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]