Commit ab6e54a6 by David Malcolm Committed by David Malcolm

testsuite: add coverage for diagnostics relating to inlining (PR tree-optimization/83336)

In theory, the diagnostics subsystem can print context information on
code inlining when diagnostics are emitted by the middle-end, describing
the chain of inlined callsites that led to a particular warning,
but PR tree-optimization/83336 describes various issues with this.

An underlying issue is that we have very little automated testing for
this code: gcc.dg/tm/pr52141.c has a test, but in general, prune.exp
filters out the various "inlined from" lines.

The following patch adds test coverage for it for C and C++ via a new
testsuite plugin, which emits a warning from the middle-end; the test
cases use dg-regexp to verify that the "inlined from" lines are
emitted correctly, with the correct function names and source locations.

Doing so requires a change to prune.exp: the dg-regexp lines have to
be handled *before* the "inlined from" lines are stripped.

gcc/testsuite/ChangeLog:
	PR tree-optimization/83336
	* g++.dg/cpp0x/missing-initializer_list-include.C: Update for
	changes to prune.exp's handling of dg-regexp.
	* g++.dg/plugin/diagnostic-test-inlining-1.C: New test case.
	* g++.dg/plugin/plugin.exp (plugin_test_list): Add it, via
	gcc.dg's plugin/diagnostic_plugin_test_inlining.c.
	* gcc.dg/plugin/diagnostic-test-inlining-1.c: New test case.
	* gcc.dg/plugin/diagnostic-test-inlining-2.c: Likewise.
	* gcc.dg/plugin/diagnostic-test-inlining-3.c: Likewise.
	* gcc.dg/plugin/diagnostic-test-inlining-4.c: Likewise.
	* gcc.dg/plugin/diagnostic_plugin_test_inlining.c: New test
	plugin.
	* gcc.dg/plugin/plugin.exp (plugin_test_list): Add them.
	* lib/prune.exp (prune_gcc_output): Move call to handle-dg-regexps
	to before the various text stripping regsup invocations,
	in particular, to before the stripping of "inlined from".

From-SVN: r255786
parent 5dd44f4e
2017-12-18 David Malcolm <dmalcolm@redhat.com>
PR tree-optimization/83336
* g++.dg/cpp0x/missing-initializer_list-include.C: Update for
changes to prune.exp's handling of dg-regexp.
* g++.dg/plugin/diagnostic-test-inlining-1.C: New test case.
* g++.dg/plugin/plugin.exp (plugin_test_list): Add it, via
gcc.dg's plugin/diagnostic_plugin_test_inlining.c.
* gcc.dg/plugin/diagnostic-test-inlining-1.c: New test case.
* gcc.dg/plugin/diagnostic-test-inlining-2.c: Likewise.
* gcc.dg/plugin/diagnostic-test-inlining-3.c: Likewise.
* gcc.dg/plugin/diagnostic-test-inlining-4.c: Likewise.
* gcc.dg/plugin/diagnostic_plugin_test_inlining.c: New test
plugin.
* gcc.dg/plugin/plugin.exp (plugin_test_list): Add them.
* lib/prune.exp (prune_gcc_output): Move call to handle-dg-regexps
to before the various text stripping regsup invocations,
in particular, to before the stripping of "inlined from".
2017-12-18 Jeff Law <law@redhat.com>
PR middle-end/83460
......
......@@ -24,5 +24,6 @@ void test (int i)
+#include <initializer_list>
/* This is padding (to avoid the generated patch containing DejaGnu
directives). */
{ dg-end-multiline-output "" }
#endif
/* { dg-do compile } */
/* { dg-options "-Wno-attributes -fdiagnostics-show-caret" } */
extern void __emit_warning (const char *message);
/* Verify that the diagnostic subsytem describes the chain of inlining
when reporting the warning. */
__attribute__((always_inline))
static void foo (void)
{
__emit_warning ("message");
}
__attribute__((always_inline))
static void bar (void)
{
foo ();
}
int main()
{
bar ();
return 0;
}
/* { dg-regexp "In function 'void foo\\(\\)'," "" } */
/* { dg-regexp " inlined from 'void bar\\(\\)' at .+/diagnostic-test-inlining-1.C:18:7," "" } */
/* { dg-regexp " inlined from 'int main\\(\\)' at .+/diagnostic-test-inlining-1.C:23:7:" "" } */
/* { dg-warning "18: message" "" { target *-*-* } 12 } */
/* { dg-begin-multiline-output "" }
__emit_warning ("message");
~~~~~~~~~~~~~~~^~~~~~~~~~~
{ dg-end-multiline-output "" } */
......@@ -65,6 +65,8 @@ set plugin_test_list [list \
{ def_plugin.c def-plugin-test.C } \
{ ../../gcc.dg/plugin/diagnostic_plugin_test_tree_expression_range.c \
diagnostic-test-expressions-1.C } \
{ ../../gcc.dg/plugin/diagnostic_plugin_test_inlining.c \
diagnostic-test-inlining-1.C } \
{ show_template_tree_color_plugin.c \
show-template-tree-color.C \
show-template-tree-color-no-elide-type.C } \
......
/* { dg-do compile } */
/* { dg-options "-Wno-attributes -fdiagnostics-show-caret" } */
extern void __emit_warning (const char *message);
__attribute__((always_inline))
static void foo (void)
{
__emit_warning ("message");
}
__attribute__((always_inline))
static void bar (void)
{
foo ();
}
int main()
{
bar ();
return 0;
}
/* Verify that the diagnostic subsytem describes the chain of inlining
when reporting the warning. */
/* { dg-regexp "In function 'foo'," "" } */
/* { dg-regexp " inlined from 'bar' at .+/diagnostic-test-inlining-1.c:15:3," "" } */
/* { dg-regexp " inlined from 'main' at .+/diagnostic-test-inlining-1.c:20:3:" "" } */
/* { dg-warning "3: message" "" { target *-*-* } 9 } */
/* { dg-begin-multiline-output "" }
__emit_warning ("message");
^~~~~~~~~~~~~~~~~~~~~~~~~~
{ dg-end-multiline-output "" } */
/* { dg-do compile } */
/* { dg-options "-Wno-attributes -fdiagnostics-show-caret" } */
extern void __emit_warning (const char *message);
#define INNER_WARNING(MSG) __emit_warning (MSG)
#define OUTER_WARNING(MSG) INNER_WARNING (MSG)
__attribute__((always_inline))
static void foo (void)
{
OUTER_WARNING ("message");
}
__attribute__((always_inline))
static void bar (void)
{
foo ();
}
int main()
{
bar ();
return 0;
}
/* Verify that the diagnostic subsytem describes both the chains of
inlining and of macro expansion when reporting the warning. */
/* { dg-regexp "In function 'foo'," "" } */
/* { dg-regexp " inlined from 'bar' at .+/diagnostic-test-inlining-2.c:19:3," "" } */
/* { dg-regexp " inlined from 'main' at .+/diagnostic-test-inlining-2.c:24:3:" "" } */
/* { dg-warning "28: message" "" { target c } 6 } */
/* { dg-begin-multiline-output "" }
#define INNER_WARNING(MSG) __emit_warning (MSG)
^~~~~~~~~~~~~~~~~~~~
{ dg-end-multiline-output "" } */
/* { dg-message "28: in expansion of macro 'INNER_WARNING'" "" { target c } 8 } */
/* { dg-begin-multiline-output "" }
#define OUTER_WARNING(MSG) INNER_WARNING (MSG)
^~~~~~~~~~~~~
{ dg-end-multiline-output "" } */
/* { dg-message "3: in expansion of macro 'OUTER_WARNING'" "" { target c } 13 } */
/* { dg-begin-multiline-output "" }
OUTER_WARNING ("message");
^~~~~~~~~~~~~
{ dg-end-multiline-output "" } */
/* { dg-do compile } */
/* { dg-options "-Wno-attributes -fdiagnostics-show-caret -O1" } */
extern void __emit_warning (const char *message);
__attribute__((always_inline))
static void foo (void)
{
__emit_warning ("message");
}
__attribute__((always_inline))
static void bar (void)
{
foo ();
}
int main()
{
bar ();
return 0;
}
/* Reproducer for PR tree-optimization/83336: when optimization is
enabled, but debuginfo isn't, the diagnostics subsystem doesn't
report the full inlining chain at a middle-end warning.
This is a copy of diagnostic-test-inlining-1.c, but with -O1.
Ideally the diagnostics subsystem would report:
In function 'foo', inlined from 'bar' at LOC A, inlined from 'main' at LOC B:
but with -O1 it only reports:
In function 'foo', inlined from 'main' at LOC A:
This test case captures this behavior. */
/* { dg-regexp "In function 'foo'," "" } */
/* { dg-regexp " inlined from 'main' at .+/diagnostic-test-inlining-3.c:15:3:" "" } */
/* { dg-warning "3: message" "" { target *-*-* } 9 } */
/* { dg-begin-multiline-output "" }
__emit_warning ("message");
^~~~~~~~~~~~~~~~~~~~~~~~~~
{ dg-end-multiline-output "" } */
/* { dg-do compile } */
/* { dg-options "-Wno-attributes -fdiagnostics-show-caret" } */
extern void __emit_warning (const char *message);
__attribute__((always_inline))
static void depth_0 (void)
{
__emit_warning ("message");
}
__attribute__((always_inline))
static void depth_1 (void)
{
depth_0 ();
}
__attribute__((always_inline))
static void depth_2 (void)
{
depth_1 ();
}
__attribute__((always_inline))
static void depth_3 (void)
{
depth_2 ();
}
__attribute__((always_inline))
static void depth_4 (void)
{
depth_3 ();
}
int main()
{
depth_4 ();
return 0;
}
/* Verify that the diagnostic subsytem describes the chain of inlining
when reporting the warning, for an example showing many levels of
inlining. */
/* { dg-regexp "In function 'depth_0'," "" } */
/* { dg-regexp " inlined from 'depth_1' at .+/diagnostic-test-inlining-4.c:15:3," "" } */
/* { dg-regexp " inlined from 'depth_2' at .+/diagnostic-test-inlining-4.c:21:3," "" } */
/* { dg-regexp " inlined from 'depth_3' at .+/diagnostic-test-inlining-4.c:27:3," "" } */
/* { dg-regexp " inlined from 'depth_4' at .+/diagnostic-test-inlining-4.c:33:3," "" } */
/* { dg-regexp " inlined from 'main' at .+/diagnostic-test-inlining-4.c:38:3:" "" } */
/* { dg-warning "3: message" "" { target *-*-* } 9 } */
/* { dg-begin-multiline-output "" }
__emit_warning ("message");
^~~~~~~~~~~~~~~~~~~~~~~~~~
{ dg-end-multiline-output "" } */
/* { dg-options "-O" } */
#include "gcc-plugin.h"
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "tree.h"
#include "stringpool.h"
#include "toplev.h"
#include "basic-block.h"
#include "hash-table.h"
#include "vec.h"
#include "ggc.h"
#include "basic-block.h"
#include "tree-ssa-alias.h"
#include "internal-fn.h"
#include "gimple-fold.h"
#include "tree-eh.h"
#include "gimple-expr.h"
#include "is-a.h"
#include "gimple.h"
#include "gimple-iterator.h"
#include "tree.h"
#include "tree-pass.h"
#include "intl.h"
#include "plugin-version.h"
#include "c-family/c-common.h"
#include "diagnostic.h"
#include "context.h"
#include "print-tree.h"
#include "cpplib.h"
#include "c-family/c-pragma.h"
#include "substring-locations.h"
int plugin_is_GPL_compatible;
/* A custom pass for emitting dummy warnings from the middle-end. */
const pass_data pass_data_test_inlining =
{
GIMPLE_PASS, /* type */
"test_inlining", /* name */
OPTGROUP_NONE, /* optinfo_flags */
TV_NONE, /* tv_id */
PROP_ssa, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
0, /* todo_flags_finish */
};
class pass_test_inlining : public gimple_opt_pass
{
public:
pass_test_inlining(gcc::context *ctxt)
: gimple_opt_pass(pass_data_test_inlining, ctxt)
{}
/* opt_pass methods: */
bool gate (function *) { return true; }
virtual unsigned int execute (function *);
}; // class pass_test_inlining
/* Determine if STMT is a call with NUM_ARGS arguments to a function
named FUNCNAME.
If so, return STMT as a gcall *. Otherwise return NULL. */
static gcall *
check_for_named_call (gimple *stmt,
const char *funcname, unsigned int num_args)
{
gcc_assert (funcname);
gcall *call = dyn_cast <gcall *> (stmt);
if (!call)
return NULL;
tree fndecl = gimple_call_fndecl (call);
if (!fndecl)
return NULL;
if (strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), funcname))
return NULL;
if (gimple_call_num_args (call) != num_args)
{
error_at (stmt->location, "expected number of args: %i (got %i)",
num_args, gimple_call_num_args (call));
return NULL;
}
return call;
}
/* Emit a warning at LOC. */
static void
emit_warning (location_t loc)
{
source_range src_range = get_range_from_loc (line_table, loc);
warning_at (loc, 0, "range %i:%i-%i:%i",
LOCATION_LINE (src_range.m_start),
LOCATION_COLUMN (src_range.m_start),
LOCATION_LINE (src_range.m_finish),
LOCATION_COLUMN (src_range.m_finish));
}
/* Code for simulating the emission of a warning from the middle-end.
Emit a warning for each call to a function named "__emit_warning". */
static void
test_inlining (gimple *stmt)
{
gcall *call = check_for_named_call (stmt, "__emit_warning", 1);
if (!call)
return;
/* We expect an ADDR_EXPR with a STRING_CST inside it for the
initial arg. */
tree t_addr_string = gimple_call_arg (call, 0);
if (TREE_CODE (t_addr_string) != ADDR_EXPR)
{
error_at (call->location, "string literal required for arg 1");
return;
}
tree t_string = TREE_OPERAND (t_addr_string, 0);
if (TREE_CODE (t_string) != STRING_CST)
{
error_at (call->location, "string literal required for arg 1");
return;
}
warning_at (call->location, 0, "%G%s", call,
TREE_STRING_POINTER (t_string));
}
/* Call test_inlining on every statement within FUN. */
unsigned int
pass_test_inlining::execute (function *fun)
{
gimple_stmt_iterator gsi;
basic_block bb;
FOR_EACH_BB_FN (bb, fun)
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
{
gimple *stmt = gsi_stmt (gsi);
test_inlining (stmt);
}
return 0;
}
/* Entrypoint for the plugin. Create and register the custom pass. */
int
plugin_init (struct plugin_name_args *plugin_info,
struct plugin_gcc_version *version)
{
struct register_pass_info pass_info;
const char *plugin_name = plugin_info->base_name;
int argc = plugin_info->argc;
struct plugin_argument *argv = plugin_info->argv;
if (!plugin_default_version_check (version, &gcc_version))
return 1;
pass_info.pass = new pass_test_inlining (g);
pass_info.reference_pass_name = "*warn_function_noreturn";
pass_info.ref_pass_instance_number = 1;
pass_info.pos_op = PASS_POS_INSERT_AFTER;
register_callback (plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL,
&pass_info);
return 0;
}
......@@ -83,6 +83,11 @@ set plugin_test_list [list \
diagnostic-test-string-literals-2.c \
diagnostic-test-string-literals-3.c \
diagnostic-test-string-literals-4.c } \
{ diagnostic_plugin_test_inlining.c \
diagnostic-test-inlining-1.c \
diagnostic-test-inlining-2.c \
diagnostic-test-inlining-3.c \
diagnostic-test-inlining-4.c } \
{ location_overflow_plugin.c \
location-overflow-test-1.c \
location-overflow-test-2.c } \
......
......@@ -28,6 +28,9 @@ proc prune_gcc_output { text } {
#send_user "Before:$text\n"
# Handle any freeform regexps.
set text [handle-dg-regexps $text]
regsub -all "(^|\n)(\[^\n\]*: )?In ((static member |lambda )?function|member|method|(copy )?constructor|destructor|instantiation|substitution|program|subroutine|block-data)\[^\n\]*" $text "" text
regsub -all "(^|\n)\[^\n\]*(: )?At (top level|global scope):\[^\n\]*" $text "" text
regsub -all "(^|\n)\[^\n\]*: (recursively )?required \[^\n\]*" $text "" text
......@@ -73,9 +76,6 @@ proc prune_gcc_output { text } {
# Call into multiline.exp to handle any multiline output directives.
set text [handle-multiline-outputs $text]
# Handle any freeform regexps.
set text [handle-dg-regexps $text]
#send_user "After:$text\n"
return $text
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment