Commit eea77d1f by David Malcolm Committed by David Malcolm

c/c++: Add fix-it hints for suggested missing #includes

gcc/c-family/ChangeLog:
	* c-common.c (try_to_locate_new_include_insertion_point): New
	function.
	(per_file_includes_t): New typedef.
	(added_includes_t): New typedef.
	(added_includes): New variable.
	(maybe_add_include_fixit): New function.
	* c-common.h (maybe_add_include_fixit): New decl.

gcc/c/ChangeLog:
	* c-decl.c (implicitly_declare): When suggesting a missing
	#include, provide a fix-it hint.

gcc/cp/ChangeLog:
	* name-lookup.c (get_std_name_hint): Add '<' and '>' around
	the header names.
	(maybe_suggest_missing_header): Update for addition of '<' and '>'
	to above.  Provide a fix-it hint.
	* pt.c: Include "gcc-rich-location.h"
	(listify): Attempt to add fix-it hint for missing
	#include <initializer_list>.
	* rtti.c: Include "gcc-rich-location.h".
	(typeid_ok_p): Attempt to add fix-it hint for missing
	#include <typeinfo>.

gcc/testsuite/ChangeLog:
	* g++.dg/cpp0x/missing-initializer_list-include.C: New test case.
	* g++.dg/lookup/missing-std-include-2.C: New test case.
	* g++.dg/lookup/missing-std-include-3.C: New test case.
	* g++.dg/rtti/missing-typeinfo-include.C: New test case.
	* gcc.dg/missing-header-fixit-1.c: New test case.
	* gcc.dg/missing-header-fixit-2.c: New test case.
	* gcc.dg/missing-header-fixit-2.h: New header.

From-SVN: r250203
parent bcf19844
2017-07-14 David Malcolm <dmalcolm@redhat.com>
* c-common.c (try_to_locate_new_include_insertion_point): New
function.
(per_file_includes_t): New typedef.
(added_includes_t): New typedef.
(added_includes): New variable.
(maybe_add_include_fixit): New function.
* c-common.h (maybe_add_include_fixit): New decl.
2017-07-10 Martin Sebor <msebor@redhat.com> 2017-07-10 Martin Sebor <msebor@redhat.com>
PR other/81345 PR other/81345
......
...@@ -8019,4 +8019,135 @@ c_family_tests (void) ...@@ -8019,4 +8019,135 @@ c_family_tests (void)
#endif /* #if CHECKING_P */ #endif /* #if CHECKING_P */
/* Attempt to locate a suitable location within FILE for a
#include directive to be inserted before. FILE should
be a string from libcpp (pointer equality is used).
LOC is the location of the relevant diagnostic.
Attempt to return the location within FILE immediately
after the last #include within that file, or the start of
that file if it has no #include directives.
Return UNKNOWN_LOCATION if no suitable location is found,
or if an error occurs. */
static location_t
try_to_locate_new_include_insertion_point (const char *file, location_t loc)
{
/* Locate the last ordinary map within FILE that ended with a #include. */
const line_map_ordinary *last_include_ord_map = NULL;
/* ...and the next ordinary map within FILE after that one. */
const line_map_ordinary *last_ord_map_after_include = NULL;
/* ...and the first ordinary map within FILE. */
const line_map_ordinary *first_ord_map_in_file = NULL;
/* Get ordinary map containing LOC (or its expansion). */
const line_map_ordinary *ord_map_for_loc = NULL;
loc = linemap_resolve_location (line_table, loc, LRK_MACRO_EXPANSION_POINT,
&ord_map_for_loc);
gcc_assert (ord_map_for_loc);
for (unsigned int i = 0; i < LINEMAPS_ORDINARY_USED (line_table); i++)
{
const line_map_ordinary *ord_map
= LINEMAPS_ORDINARY_MAP_AT (line_table, i);
const line_map_ordinary *from = INCLUDED_FROM (line_table, ord_map);
if (from)
if (from->to_file == file)
{
last_include_ord_map = from;
last_ord_map_after_include = NULL;
}
if (ord_map->to_file == file)
{
if (!first_ord_map_in_file)
first_ord_map_in_file = ord_map;
if (last_include_ord_map && !last_ord_map_after_include)
last_ord_map_after_include = ord_map;
}
/* Stop searching when reaching the ord_map containing LOC,
as it makes no sense to provide fix-it hints that appear
after the diagnostic in question. */
if (ord_map == ord_map_for_loc)
break;
}
/* Determine where to insert the #include. */
const line_map_ordinary *ord_map_for_insertion;
/* We want the next ordmap in the file after the last one that's a
#include, but failing that, the start of the file. */
if (last_ord_map_after_include)
ord_map_for_insertion = last_ord_map_after_include;
else
ord_map_for_insertion = first_ord_map_in_file;
if (!ord_map_for_insertion)
return UNKNOWN_LOCATION;
/* The "start_location" is column 0, meaning "the whole line".
rich_location and edit_context can't cope with this, so use
column 1 instead. */
location_t col_0 = ord_map_for_insertion->start_location;
return linemap_position_for_loc_and_offset (line_table, col_0, 1);
}
/* A map from filenames to sets of headers added to them, for
ensuring idempotency within maybe_add_include_fixit. */
/* The values within the map. We need string comparison as there's
no guarantee that two different diagnostics that are recommending
adding e.g. "<stdio.h>" are using the same buffer. */
typedef hash_set <const char *, nofree_string_hash> per_file_includes_t;
/* The map itself. We don't need string comparison for the filename keys,
as they come from libcpp. */
typedef hash_map <const char *, per_file_includes_t *> added_includes_t;
static added_includes_t *added_includes;
/* Attempt to add a fix-it hint to RICHLOC, adding "#include HEADER\n"
in a suitable location within the file of RICHLOC's primary
location.
This function is idempotent: a header will be added at most once to
any given file. */
void
maybe_add_include_fixit (rich_location *richloc, const char *header)
{
location_t loc = richloc->get_loc ();
const char *file = LOCATION_FILE (loc);
if (!file)
return;
/* Idempotency: don't add the same header more than once to a given file. */
if (!added_includes)
added_includes = new added_includes_t ();
per_file_includes_t *&set = added_includes->get_or_insert (file);
if (set)
if (set->contains (header))
/* ...then we've already added HEADER to that file. */
return;
if (!set)
set = new per_file_includes_t ();
set->add (header);
/* Attempt to locate a suitable place for the new directive. */
location_t include_insert_loc
= try_to_locate_new_include_insertion_point (file, loc);
if (include_insert_loc == UNKNOWN_LOCATION)
return;
char *text = xasprintf ("#include %s\n", header);
richloc->add_fixit_insert_before (include_insert_loc, text);
free (text);
}
#include "gt-c-family-c-common.h" #include "gt-c-family-c-common.h"
...@@ -1556,6 +1556,8 @@ excess_precision_mode_join (enum flt_eval_method, enum flt_eval_method); ...@@ -1556,6 +1556,8 @@ excess_precision_mode_join (enum flt_eval_method, enum flt_eval_method);
extern int c_flt_eval_method (bool ts18661_p); extern int c_flt_eval_method (bool ts18661_p);
extern void add_no_sanitize_value (tree node, unsigned int flags); extern void add_no_sanitize_value (tree node, unsigned int flags);
extern void maybe_add_include_fixit (rich_location *, const char *);
#if CHECKING_P #if CHECKING_P
namespace selftest { namespace selftest {
/* Declarations for specific families of tests within c-family, /* Declarations for specific families of tests within c-family,
......
2017-07-14 David Malcolm <dmalcolm@redhat.com>
* c-decl.c (implicitly_declare): When suggesting a missing
#include, provide a fix-it hint.
2017-07-06 David Malcolm <dmalcolm@redhat.com> 2017-07-06 David Malcolm <dmalcolm@redhat.com>
* c-lang.c (selftest::run_c_tests): Move body to c_family_tests, * c-lang.c (selftest::run_c_tests): Move body to c_family_tests,
......
...@@ -3386,8 +3386,14 @@ implicitly_declare (location_t loc, tree functionid) ...@@ -3386,8 +3386,14 @@ implicitly_declare (location_t loc, tree functionid)
const char *header const char *header
= header_for_builtin_fn (DECL_FUNCTION_CODE (decl)); = header_for_builtin_fn (DECL_FUNCTION_CODE (decl));
if (header != NULL && warned) if (header != NULL && warned)
inform (loc, "include %qs or provide a declaration of %qD", {
header, decl); rich_location richloc (line_table, loc);
maybe_add_include_fixit (&richloc, header);
inform_at_rich_loc
(&richloc,
"include %qs or provide a declaration of %qD",
header, decl);
}
newtype = TREE_TYPE (decl); newtype = TREE_TYPE (decl);
} }
} }
......
2017-07-14 David Malcolm <dmalcolm@redhat.com>
* name-lookup.c (get_std_name_hint): Add '<' and '>' around
the header names.
(maybe_suggest_missing_header): Update for addition of '<' and '>'
to above. Provide a fix-it hint.
* pt.c: Include "gcc-rich-location.h"
(listify): Attempt to add fix-it hint for missing
#include <initializer_list>.
* rtti.c: Include "gcc-rich-location.h".
(typeid_ok_p): Attempt to add fix-it hint for missing
#include <typeinfo>.
2017-07-12 Jason Merrill <jason@redhat.com> 2017-07-12 Jason Merrill <jason@redhat.com>
P0512R0 - Deduction from an initializer list. P0512R0 - Deduction from an initializer list.
......
...@@ -4760,7 +4760,7 @@ suggest_alternatives_for (location_t location, tree name, ...@@ -4760,7 +4760,7 @@ suggest_alternatives_for (location_t location, tree name,
/* Subroutine of maybe_suggest_missing_header for handling unrecognized names /* Subroutine of maybe_suggest_missing_header for handling unrecognized names
for some of the most common names within "std::". for some of the most common names within "std::".
Given non-NULL NAME, a name for lookup within "std::", return the header Given non-NULL NAME, a name for lookup within "std::", return the header
name defining it within the C++ Standard Library (without '<' and '>'), name defining it within the C++ Standard Library (with '<' and '>'),
or NULL. */ or NULL. */
static const char * static const char *
...@@ -4773,61 +4773,61 @@ get_std_name_hint (const char *name) ...@@ -4773,61 +4773,61 @@ get_std_name_hint (const char *name)
}; };
static const std_name_hint hints[] = { static const std_name_hint hints[] = {
/* <array>. */ /* <array>. */
{"array", "array"}, // C++11 {"array", "<array>"}, // C++11
/* <deque>. */ /* <deque>. */
{"deque", "deque"}, {"deque", "<deque>"},
/* <forward_list>. */ /* <forward_list>. */
{"forward_list", "forward_list"}, // C++11 {"forward_list", "<forward_list>"}, // C++11
/* <fstream>. */ /* <fstream>. */
{"basic_filebuf", "fstream"}, {"basic_filebuf", "<fstream>"},
{"basic_ifstream", "fstream"}, {"basic_ifstream", "<fstream>"},
{"basic_ofstream", "fstream"}, {"basic_ofstream", "<fstream>"},
{"basic_fstream", "fstream"}, {"basic_fstream", "<fstream>"},
/* <iostream>. */ /* <iostream>. */
{"cin", "iostream"}, {"cin", "<iostream>"},
{"cout", "iostream"}, {"cout", "<iostream>"},
{"cerr", "iostream"}, {"cerr", "<iostream>"},
{"clog", "iostream"}, {"clog", "<iostream>"},
{"wcin", "iostream"}, {"wcin", "<iostream>"},
{"wcout", "iostream"}, {"wcout", "<iostream>"},
{"wclog", "iostream"}, {"wclog", "<iostream>"},
/* <list>. */ /* <list>. */
{"list", "list"}, {"list", "<list>"},
/* <map>. */ /* <map>. */
{"map", "map"}, {"map", "<map>"},
{"multimap", "map"}, {"multimap", "<map>"},
/* <queue>. */ /* <queue>. */
{"queue", "queue"}, {"queue", "<queue>"},
{"priority_queue", "queue"}, {"priority_queue", "<queue>"},
/* <ostream>. */ /* <ostream>. */
{"ostream", "ostream"}, {"ostream", "<ostream>"},
{"wostream", "ostream"}, {"wostream", "<ostream>"},
{"ends", "ostream"}, {"ends", "<ostream>"},
{"flush", "ostream"}, {"flush", "<ostream>"},
{"endl", "ostream"}, {"endl", "<ostream>"},
/* <set>. */ /* <set>. */
{"set", "set"}, {"set", "<set>"},
{"multiset", "set"}, {"multiset", "<set>"},
/* <sstream>. */ /* <sstream>. */
{"basic_stringbuf", "sstream"}, {"basic_stringbuf", "<sstream>"},
{"basic_istringstream", "sstream"}, {"basic_istringstream", "<sstream>"},
{"basic_ostringstream", "sstream"}, {"basic_ostringstream", "<sstream>"},
{"basic_stringstream", "sstream"}, {"basic_stringstream", "<sstream>"},
/* <stack>. */ /* <stack>. */
{"stack", "stack"}, {"stack", "<stack>"},
/* <string>. */ /* <string>. */
{"string", "string"}, {"string", "<string>"},
{"wstring", "string"}, {"wstring", "<string>"},
{"u16string", "string"}, {"u16string", "<string>"},
{"u32string", "string"}, {"u32string", "<string>"},
/* <unordered_map>. */ /* <unordered_map>. */
{"unordered_map", "unordered_map"}, // C++11 {"unordered_map", "<unordered_map>"}, // C++11
{"unordered_multimap", "unordered_map"}, // C++11 {"unordered_multimap", "<unordered_map>"}, // C++11
/* <unordered_set>. */ /* <unordered_set>. */
{"unordered_set", "unordered_set"}, // C++11 {"unordered_set", "<unordered_set>"}, // C++11
{"unordered_multiset", "unordered_set"}, // C++11 {"unordered_multiset", "<unordered_set>"}, // C++11
/* <vector>. */ /* <vector>. */
{"vector", "vector"}, {"vector", "<vector>"},
}; };
const size_t num_hints = sizeof (hints) / sizeof (hints[0]); const size_t num_hints = sizeof (hints) / sizeof (hints[0]);
for (size_t i = 0; i < num_hints; i++) for (size_t i = 0; i < num_hints; i++)
...@@ -4858,10 +4858,14 @@ maybe_suggest_missing_header (location_t location, tree name, tree scope) ...@@ -4858,10 +4858,14 @@ maybe_suggest_missing_header (location_t location, tree name, tree scope)
const char *name_str = IDENTIFIER_POINTER (name); const char *name_str = IDENTIFIER_POINTER (name);
const char *header_hint = get_std_name_hint (name_str); const char *header_hint = get_std_name_hint (name_str);
if (header_hint) if (header_hint)
inform (location, {
"%<std::%s%> is defined in header %<<%s>%>;" gcc_rich_location richloc (location);
" did you forget to %<#include <%s>%>?", maybe_add_include_fixit (&richloc, header_hint);
name_str, header_hint, header_hint); inform_at_rich_loc (&richloc,
"%<std::%s%> is defined in header %qs;"
" did you forget to %<#include %s%>?",
name_str, header_hint, header_hint);
}
} }
/* Look for alternatives for NAME, an IDENTIFIER_NODE for which name /* Look for alternatives for NAME, an IDENTIFIER_NODE for which name
......
...@@ -40,6 +40,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -40,6 +40,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree-iterator.h" #include "tree-iterator.h"
#include "type-utils.h" #include "type-utils.h"
#include "gimplify.h" #include "gimplify.h"
#include "gcc-rich-location.h"
/* The type of functions taking a tree, and some additional data, and /* The type of functions taking a tree, and some additional data, and
returning an int. */ returning an int. */
...@@ -24867,8 +24868,12 @@ listify (tree arg) ...@@ -24867,8 +24868,12 @@ listify (tree arg)
if (!std_init_list || !DECL_CLASS_TEMPLATE_P (std_init_list)) if (!std_init_list || !DECL_CLASS_TEMPLATE_P (std_init_list))
{ {
error ("deducing from brace-enclosed initializer list requires " gcc_rich_location richloc (input_location);
"#include <initializer_list>"); maybe_add_include_fixit (&richloc, "<initializer_list>");
error_at_rich_loc (&richloc,
"deducing from brace-enclosed initializer list"
" requires #include <initializer_list>");
return error_mark_node; return error_mark_node;
} }
tree argvec = make_tree_vec (1); tree argvec = make_tree_vec (1);
......
...@@ -29,6 +29,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -29,6 +29,7 @@ along with GCC; see the file COPYING3. If not see
#include "intl.h" #include "intl.h"
#include "stor-layout.h" #include "stor-layout.h"
#include "c-family/c-pragma.h" #include "c-family/c-pragma.h"
#include "gcc-rich-location.h"
/* C++ returns type information to the user in struct type_info /* C++ returns type information to the user in struct type_info
objects. We also use type information to implement dynamic_cast and objects. We also use type information to implement dynamic_cast and
...@@ -316,7 +317,12 @@ typeid_ok_p (void) ...@@ -316,7 +317,12 @@ typeid_ok_p (void)
if (!COMPLETE_TYPE_P (const_type_info_type_node)) if (!COMPLETE_TYPE_P (const_type_info_type_node))
{ {
error ("must %<#include <typeinfo>%> before using %<typeid%>"); gcc_rich_location richloc (input_location);
maybe_add_include_fixit (&richloc, "<typeinfo>");
error_at_rich_loc (&richloc,
"must %<#include <typeinfo>%> before using"
" %<typeid%>");
return false; return false;
} }
......
2017-07-14 David Malcolm <dmalcolm@redhat.com>
* g++.dg/cpp0x/missing-initializer_list-include.C: New test case.
* g++.dg/lookup/missing-std-include-2.C: New test case.
* g++.dg/lookup/missing-std-include-3.C: New test case.
* g++.dg/rtti/missing-typeinfo-include.C: New test case.
* gcc.dg/missing-header-fixit-1.c: New test case.
* gcc.dg/missing-header-fixit-2.c: New test case.
* gcc.dg/missing-header-fixit-2.h: New header.
2017-07-13 David Malcolm <dmalcolm@redhat.com> 2017-07-13 David Malcolm <dmalcolm@redhat.com>
PR c/81405 PR c/81405
......
/* This is padding (to avoid the generated patch containing DejaGnu
directives). */
/* { dg-options "-fdiagnostics-generate-patch" } */
// { dg-do compile { target c++11 } }
void test (int i)
{
auto a = { &i }; // { dg-error "deducing from brace-enclosed initializer list requires #include <initializer_list>" }
}
/* Verify the output from -fdiagnostics-generate-patch.
We expect the patch to begin with a header, containing this
source filename, via an absolute path.
Given the path, we can only capture it via regexps. */
/* { dg-regexp "\\-\\-\\- .*" } */
/* { dg-regexp "\\+\\+\\+ .*" } */
/* Use #if 0/#endif rather than comments, to allow the text to contain
a comment. */
#if 0
{ dg-begin-multiline-output "" }
@@ -1,3 +1,4 @@
+#include <initializer_list>
/* This is padding (to avoid the generated patch containing DejaGnu
directives). */
{ dg-end-multiline-output "" }
#endif
/* Example of fix-it hints that add #include directives,
adding them after a pre-existing #include. */
/* { dg-options "-fdiagnostics-generate-patch" } */
/* This is padding (to avoid the generated patch containing DejaGnu
directives). */
#include <stdio.h>
void test (void)
{
std::string s ("hello world"); // { dg-error ".string. is not a member of .std." }
// { dg-message ".std::string. is defined in header .<string>.; did you forget to .#include <string>.?" "" { target *-*-* } .-1 }
std::cout << 10; // { dg-error ".cout. is not a member of .std." }
// { dg-message ".std::cout. is defined in header .<iostream>.; did you forget to .#include <iostream>.?" "" { target *-*-* } .-1 }
}
/* Same again, to test idempotency of the added "#include" fix-it. */
void test_2 (void)
{
std::string s ("hello again"); // { dg-error ".string. is not a member of .std." }
// { dg-message ".std::string. is defined in header .<string>.; did you forget to .#include <string>.?" "" { target *-*-* } .-1 }
std::cout << 10; // { dg-error ".cout. is not a member of .std." }
// { dg-message ".std::cout. is defined in header .<iostream>.; did you forget to .#include <iostream>.?" "" { target *-*-* } .-1 }
}
/* Verify the output from -fdiagnostics-generate-patch.
We expect the patch to begin with a header, containing this
source filename, via an absolute path.
Given the path, we can only capture it via regexps. */
/* { dg-regexp "\\-\\-\\- .*" } */
/* { dg-regexp "\\+\\+\\+ .*" } */
/* Verify the hunks within the patch.
Use #if 0/#endif rather than comments, to allow the text to contain
a comment.
We expect a "#include <string>" and "#include <iostream>" to each have been
added once, immediately below the last #include. */
#if 0
{ dg-begin-multiline-output "" }
@@ -7,6 +7,8 @@
directives). */
#include <stdio.h>
+#include <string>
+#include <iostream>
void test (void)
{
{ dg-end-multiline-output "" }
#endif
/* Example of where the error occurs before the first #include,
which in this case happens to be the missing header.
For this case, expect to insert the #include at the top of the file. */
/* { dg-options "-fdiagnostics-generate-patch" } */
void test ()
{
std::string test; // { dg-error ".string. is not a member of .std." }
// { dg-message ".std::string. is defined in header .<string>.; did you forget to .#include <string>.?" "" { target *-*-* } .-1 }
}
#include <string>
/* Verify the output from -fdiagnostics-generate-patch.
We expect the patch to begin with a header, containing this
source filename, via an absolute path.
Given the path, we can only capture it via regexps. */
/* { dg-regexp "\\-\\-\\- .*" } */
/* { dg-regexp "\\+\\+\\+ .*" } */
/* Verify the hunks within the patch.
Use #if 0/#endif rather than comments, to allow the text to contain
a comment.
We expect a "#include <string>" have been added once, at the top
of the file. */
#if 0
{ dg-begin-multiline-output "" }
@@ -1,3 +1,4 @@
+#include <string>
/* Example of where the error occurs before the first #include,
which in this case happens to be the missing header.
For this case, expect to insert the #include at the top of the file. */
{ dg-end-multiline-output "" }
#endif
/* This is padding (to avoid the generated patch containing DejaGnu
directives). */
/* { dg-options "-fdiagnostics-generate-patch" } */
void test()
{
typeid(void); // { dg-error "must '#include <typeinfo>' before using 'typeid'" }
}
/* Verify the output from -fdiagnostics-generate-patch.
We expect the patch to begin with a header, containing this
source filename, via an absolute path.
Given the path, we can only capture it via regexps. */
/* { dg-regexp "\\-\\-\\- .*" } */
/* { dg-regexp "\\+\\+\\+ .*" } */
/* Use #if 0/#endif rather than comments, to allow the text to contain
a comment. */
#if 0
{ dg-begin-multiline-output "" }
@@ -1,3 +1,4 @@
+#include <typeinfo>
/* This is padding (to avoid the generated patch containing DejaGnu
directives). */
{ dg-end-multiline-output "" }
#endif
/* Example of a fix-it hint that adds a #include directive,
adding them to the top of the file, given that there is no
pre-existing #include. */
/* This is padding (to avoid the generated patch containing DejaGnu
directives). */
/* { dg-options "-fdiagnostics-generate-patch" } */
void test (int i, int j)
{
printf ("%i of %i\n", i, j); /* { dg-warning "implicit declaration" } */
/* { dg-message "include '<stdio.h>' or provide a declaration of 'printf'" "" { target *-*-* } .-1 } */
}
/* Verify the output from -fdiagnostics-generate-patch.
We expect the patch to begin with a header, containing this
source filename, via an absolute path.
Given the path, we can only capture it via regexps. */
/* { dg-regexp "\\-\\-\\- .*" } */
/* { dg-regexp "\\+\\+\\+ .*" } */
/* Use #if 0/#endif rather than comments, to allow the text to contain
a comment. */
#if 0
{ dg-begin-multiline-output "" }
@@ -1,3 +1,4 @@
+#include <stdio.h>
/* Example of a fix-it hint that adds a #include directive,
adding them to the top of the file, given that there is no
pre-existing #include. */
{ dg-end-multiline-output "" }
#endif
/* FIXME: should we attempt to skip leading comments when determining the
insertion location?
Similarly, should we attempt to be within single-inclusion guards, etc? */
/* Verify that when we suggest adding #include directives that they
are added to the affected file. */
/* The following header file is missing a "#include <stdio.h>". */
#include "missing-header-fixit-2.h"
/* These directives actually apply to the header. */
/* { dg-warning "implicit declaration of function 'printf'" "" { target *-*-* } 6 } */
/* { dg-warning "incompatible implicit declaration of built-in function 'printf'" "" { target *-*-* } 6 } */
/* { dg-options "-fdiagnostics-generate-patch" } */
/* Verify the output from -fdiagnostics-generate-patch.
We expect the patch to begin with a header, containing the
filename of the header, via an absolute path.
Given the path, we can only capture it via regexps. */
/* { dg-regexp "\\-\\-\\- .*" } */
/* { dg-regexp "\\+\\+\\+ .*" } */
/* Use #if 0/#endif rather than comments, to allow the text to contain
a comment.
We expect the *header* to have been patched, adding the missing include. */
#if 0
{ dg-begin-multiline-output "" }
@@ -1,3 +1,4 @@
+#include <stdio.h>
/* This is missing-header-fixit-2.h, for use by
missing-header-fixit-2.c */
{ dg-end-multiline-output "" }
#endif
/* This is missing-header-fixit-2.h, for use by
missing-header-fixit-2.c */
void test (int i, int j)
{
printf ("%i of %i\n", i, j);
}
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