This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Support printing inlining call stack in diagnostic messages (take 2)
- From: Jakub Jelinek <jakub at redhat dot com>
- To: Gabriel Dos Reis <gdr at cs dot tamu dot edu>, Janis Johnson <janis187 at us dot ibm dot com>, Jan Hubicka <hubicka at ucw dot cz>, gcc-patches at gcc dot gnu dot org
- Date: Tue, 11 Sep 2007 09:19:53 -0400
- Subject: [PATCH] Support printing inlining call stack in diagnostic messages (take 2)
- References: <20070831190520.GM2063@devserv.devel.redhat.com> <20070831192512.GA19281@caradoc.them.org> <20070910112148.GB20571@devserv.devel.redhat.com> <20070910155635.GA10859@caradoc.them.org>
- Reply-to: Jakub Jelinek <jakub at redhat dot com>
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