@@ -48,6 +48,7 @@ along with GCC; see the file COPYING3. If not see
#include "gimplify.h"
#include "substring-locations.h"
#include "spellcheck.h"
+#include "gcc-rich-location.h"
#include "selftest.h"
cpp_reader *parse_in; /* Declared in c-pragma.h. */
@@ -8405,6 +8406,38 @@ maybe_suggest_missing_token_insertion (rich_location *richloc,
}
}
+/* Potentially emit a note about likely missing '&' or '*',
+ depending on EXPR and EXPECTED_TYPE. */
+
+void
+maybe_emit_indirection_note (location_t loc,
+ tree expr, tree expected_type)
+{
+ gcc_assert (expr);
+ gcc_assert (expected_type);
+
+ tree actual_type = TREE_TYPE (expr);
+
+ /* Missing '&'. */
+ if (TREE_CODE (expected_type) == POINTER_TYPE
+ && same_type_p (actual_type, TREE_TYPE (expected_type))
+ && lvalue_p (expr))
+ {
+ gcc_rich_location richloc (loc);
+ richloc.add_fixit_insert_before ("&");
+ inform (&richloc, "possible fix: take the address with %qs", "&");
+ }
+
+ /* Missing '*'. */
+ if (TREE_CODE (actual_type) == POINTER_TYPE
+ && same_type_p (TREE_TYPE (actual_type), expected_type))
+ {
+ gcc_rich_location richloc (loc);
+ richloc.add_fixit_insert_before ("*");
+ inform (&richloc, "possible fix: dereference with %qs", "*");
+ }
+}
+
#if CHECKING_P
namespace selftest {
@@ -1340,8 +1340,12 @@ extern void maybe_add_include_fixit (rich_location *, const char *, bool);
extern void maybe_suggest_missing_token_insertion (rich_location *richloc,
enum cpp_ttype token_type,
location_t prev_token_loc);
+extern void maybe_emit_indirection_note (location_t loc,
+ tree expr, tree expected_type);
extern tree braced_list_to_string (tree, tree);
+extern bool same_type_p (tree type1, tree type2);
+
#if CHECKING_P
namespace selftest {
/* Declarations for specific families of tests within c-family,
@@ -1003,6 +1003,16 @@ common_type (tree t1, tree t2)
return c_common_type (t1, t2);
}
+/* C implementation of same_type_p.
+ Returns true iff TYPE1 and TYPE2 are the same type, in the usual
+ sense of `same'. */
+
+bool
+same_type_p (tree type1, tree type2)
+{
+ return comptypes (type1, type2) == 1;
+}
+
/* Return 1 if TYPE1 and TYPE2 are compatible types for assignment
or various other operations. Return 2 if they are compatible
but a warning may be needed if you use them together. */
@@ -7061,7 +7071,10 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
if (pedwarn (&richloc, OPT_Wint_conversion,
"passing argument %d of %qE makes pointer from "
"integer without a cast", parmnum, rname))
- inform_for_arg (fundecl, expr_loc, parmnum, type, rhstype);
+ {
+ maybe_emit_indirection_note (expr_loc, rhs, type);
+ inform_for_arg (fundecl, expr_loc, parmnum, type, rhstype);
+ }
}
break;
case ic_assign:
@@ -7097,7 +7110,10 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
if (pedwarn (&richloc, OPT_Wint_conversion,
"passing argument %d of %qE makes integer from "
"pointer without a cast", parmnum, rname))
- inform_for_arg (fundecl, expr_loc, parmnum, type, rhstype);
+ {
+ maybe_emit_indirection_note (expr_loc, rhs, type);
+ inform_for_arg (fundecl, expr_loc, parmnum, type, rhstype);
+ }
}
break;
case ic_assign:
@@ -6862,6 +6862,8 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
complained = permerror (&richloc,
"invalid conversion from %qH to %qI",
TREE_TYPE (expr), totype);
+ if (complained)
+ maybe_emit_indirection_note (loc, expr, totype);
}
if (complained && fn)
inform (get_fndecl_argument_location (fn, argnum),
@@ -671,11 +671,6 @@ typedef struct ptrmem_cst * ptrmem_cst_t;
#define REINTERPRET_CAST_P(NODE) \
TREE_LANG_FLAG_0 (NOP_EXPR_CHECK (NODE))
-/* Returns nonzero iff TYPE1 and TYPE2 are the same type, in the usual
- sense of `same'. */
-#define same_type_p(TYPE1, TYPE2) \
- comptypes ((TYPE1), (TYPE2), COMPARE_STRICT)
-
/* Returns nonzero iff NODE is a declaration for the global function
`main'. */
#define DECL_MAIN_P(NODE) \
@@ -1448,6 +1448,16 @@ structural_comptypes (tree t1, tree t2, int strict)
return comp_type_attributes (t1, t2);
}
+/* C++ implementation of same_type_p.
+ Returns true iff TYPE1 and TYPE2 are the same type, in the usual
+ sense of `same'. */
+
+bool
+same_type_p (tree type1, tree type2)
+{
+ return comptypes (type1, type2, COMPARE_STRICT);
+}
+
/* Return true if T1 and T2 are related as allowed by STRICT. STRICT
is a bitwise-or of the COMPARE_* flags. */
new file mode 100644
@@ -0,0 +1,299 @@
+/* { dg-options "-fdiagnostics-show-caret" } */
+
+void takes_int_ptr(int*);
+void takes_char_ptr(char*);
+void takes_int(int);
+int returns_int(void);
+
+int ivar;
+char cvar;
+int *int_ptr;
+char *char_ptr;
+
+void test_1 (void)
+{
+ takes_int_ptr(&ivar);
+ takes_int_ptr(int_ptr);
+ takes_char_ptr(&cvar);
+ takes_char_ptr(char_ptr);
+
+ ivar = 42;
+ cvar = 'b';
+ int_ptr = &ivar;
+ char_ptr = &cvar;
+}
+
+void test_2 (void)
+{
+ takes_int_ptr(ivar); /* { dg-warning "" "" { target c } } */
+ /* { dg-error "" "" { target c++ } .-1 } */
+ /* { dg-message "possible fix: take the address with '&'" "" { target *-*-* } .-2 } */
+
+ /* Expect an '&' fix-it hint. */
+ /* { dg-begin-multiline-output "" }
+ takes_int_ptr(ivar);
+ ^~~~
+ |
+ int
+ { dg-end-multiline-output "" } */
+ /* { dg-begin-multiline-output "" }
+ takes_int_ptr(ivar);
+ ^~~~
+ &
+ { dg-end-multiline-output "" } */
+ /* { dg-begin-multiline-output "" }
+ void takes_int_ptr(int*);
+ ^~~~
+ { dg-end-multiline-output "" } */
+}
+
+void test_3 (void)
+{
+ takes_int_ptr(cvar); /* { dg-warning "" "" { target c } } */
+ /* { dg-error "" "" { target c++ } .-1 } */
+
+ /* Don't expect an '&' fix-it hint. */
+ /* { dg-begin-multiline-output "" }
+ takes_int_ptr(cvar);
+ ^~~~
+ |
+ char
+ { dg-end-multiline-output "" } */
+ /* { dg-begin-multiline-output "" }
+ void takes_int_ptr(int*);
+ ^~~~
+ { dg-end-multiline-output "" } */
+}
+
+void test_4 (void)
+{
+ takes_char_ptr(ivar); /* { dg-warning "" "" { target c } } */
+ /* { dg-error "" "" { target c++ } .-1 } */
+
+ /* Don't expect an '&' fix-it hint. */
+ /* { dg-begin-multiline-output "" }
+ takes_char_ptr(ivar);
+ ^~~~
+ |
+ int
+ { dg-end-multiline-output "" } */
+ /* { dg-begin-multiline-output "" }
+ void takes_char_ptr(char*);
+ ^~~~~
+ { dg-end-multiline-output "" } */
+}
+
+void test_5 (void)
+{
+ takes_char_ptr(cvar); /* { dg-warning "" "" { target c } } */
+ /* { dg-error "" "" { target c++ } .-1 } */
+
+ /* Expect an '&' fix-it hint. */
+ /* { dg-begin-multiline-output "" }
+ takes_char_ptr(cvar);
+ ^~~~
+ |
+ char
+ { dg-end-multiline-output "" } */
+ /* { dg-begin-multiline-output "" }
+ takes_char_ptr(cvar);
+ ^~~~
+ &
+ { dg-end-multiline-output "" } */
+ /* { dg-begin-multiline-output "" }
+ void takes_char_ptr(char*);
+ ^~~~~
+ { dg-end-multiline-output "" } */
+}
+
+void test_6 (void)
+{
+ takes_int(int_ptr); /* { dg-warning "" "" { target c } } */
+ /* { dg-error "" "" { target c++ } .-1 } */
+ /* { dg-message "possible fix: dereference with '*'" "" { target *-*-* } .-2 } */
+
+ /* Expect a '*' fix-it hint. */
+ /* { dg-begin-multiline-output "" }
+ takes_int(int_ptr);
+ ^~~~~~~
+ |
+ int *
+ { dg-end-multiline-output "" { target c } } */
+ /* { dg-begin-multiline-output "" }
+ takes_int(int_ptr);
+ ^~~~~~~
+ |
+ int*
+ { dg-end-multiline-output "" { target c++ } } */
+ /* { dg-begin-multiline-output "" }
+ takes_int(int_ptr);
+ ^~~~~~~
+ *
+ { dg-end-multiline-output "" } */
+ /* { dg-begin-multiline-output "" }
+ void takes_int(int);
+ ^~~
+ { dg-end-multiline-output "" } */
+}
+
+void test_7 (void)
+{
+ takes_int(char_ptr); /* { dg-warning "" "" { target c } } */
+ /* { dg-error "" "" { target c++ } .-1 } */
+
+ /* Don't expect a '*' fix-it hint. */
+ /* { dg-begin-multiline-output "" }
+ takes_int(char_ptr);
+ ^~~~~~~~
+ |
+ char *
+ { dg-end-multiline-output "" { target c } } */
+ /* { dg-begin-multiline-output "" }
+ takes_int(char_ptr);
+ ^~~~~~~~
+ |
+ char*
+ { dg-end-multiline-output "" { target c++ } } */
+ /* { dg-begin-multiline-output "" }
+ void takes_int(int);
+ ^~~
+ { dg-end-multiline-output "" } */
+}
+
+void test_8 (void)
+{
+ ivar = int_ptr; /* { dg-warning "" "" { target c } } */
+ /* { dg-error "" "" { target c++ } .-1 } */
+
+ /* Expect a fix-it hint from the C++ FE, but not from C (due to missing
+ location). */
+ /* { dg-begin-multiline-output "" }
+ ivar = int_ptr;
+ ^~~~~~~
+ |
+ int*
+ { dg-end-multiline-output "" { target c++ } } */
+ /* { dg-begin-multiline-output "" }
+ ivar = int_ptr;
+ ^~~~~~~
+ *
+ { dg-end-multiline-output "" { target c++ } } */
+ /* { dg-begin-multiline-output "" }
+ ivar = int_ptr;
+ ^
+ { dg-end-multiline-output "" { target c } } */
+}
+
+void test_9 (void)
+{
+ cvar = int_ptr; /* { dg-warning "" "" { target c } } */
+ /* { dg-error "" "" { target c++ } .-1 } */
+
+ /* Don't expect a '*' fix-it hint. */
+ /* { dg-begin-multiline-output "" }
+ cvar = int_ptr;
+ ^~~~~~~
+ |
+ int*
+ { dg-end-multiline-output "" { target c++ } } */
+ /* { dg-begin-multiline-output "" }
+ cvar = int_ptr;
+ ^
+ { dg-end-multiline-output "" { target c } } */
+}
+
+void test_10 (void)
+{
+ int_ptr = ivar; /* { dg-warning "" "" { target c } } */
+ /* { dg-error "" "" { target c++ } .-1 } */
+
+ /* Expect a fix-it hint from the C++ FE, but not from C (due to missing
+ location). */
+ /* { dg-begin-multiline-output "" }
+ int_ptr = ivar;
+ ^~~~
+ |
+ int
+ { dg-end-multiline-output "" { target c++ } } */
+ /* { dg-begin-multiline-output "" }
+ int_ptr = ivar;
+ ^~~~
+ &
+ { dg-end-multiline-output "" { target c++ } } */
+ /* { dg-begin-multiline-output "" }
+ int_ptr = ivar;
+ ^
+ { dg-end-multiline-output "" { target c } } */
+}
+
+void test_11 (void)
+{
+ char_ptr = ivar; /* { dg-warning "" "" { target c } } */
+ /* { dg-error "" "" { target c++ } .-1 } */
+
+ /* Don't expect a fix-it hint, due to mismatching types. */
+ /* { dg-begin-multiline-output "" }
+ char_ptr = ivar;
+ ^~~~
+ |
+ int
+ { dg-end-multiline-output "" { target c++ } } */
+ /* { dg-begin-multiline-output "" }
+ char_ptr = ivar;
+ ^
+ { dg-end-multiline-output "" { target c } } */
+}
+
+/* We shouldn't offer '&' fix-it hints for non-lvalues. */
+
+void test_12 (void)
+{
+ takes_int_ptr (returns_int ()); /* { dg-warning "" "" { target c } } */
+ /* { dg-error "" "" { target c++ } .-1 } */
+
+ /* { dg-begin-multiline-output "" }
+ takes_int_ptr (returns_int ());
+ ^~~~~~~~~~~~~~
+ |
+ int
+ { dg-end-multiline-output "" { target c } } */
+ /* { dg-begin-multiline-output "" }
+ takes_int_ptr (returns_int ());
+ ~~~~~~~~~~~~^~
+ |
+ int
+ { dg-end-multiline-output "" { target c++ } } */
+ /* { dg-begin-multiline-output "" }
+ void takes_int_ptr(int*);
+ ^~~~
+ { dg-end-multiline-output "" } */
+}
+
+/* Ignore typedefs when offering fix-it hints. */
+
+typedef int typedef_int_t;
+typedef_int_t typedef_int_t_var;
+
+void test_13 (void)
+{
+ takes_int_ptr (typedef_int_t_var); /* { dg-warning "" "" { target c } } */
+ /* { dg-error "" "" { target c++ } .-1 } */
+ /* { dg-message "possible fix: take the address with '&'" "" { target *-*-* } .-2 } */
+
+ /* Expect an '&' fix-it hint. */
+ /* { dg-begin-multiline-output "" }
+ takes_int_ptr (typedef_int_t_var);
+ ^~~~~~~~~~~~~~~~~
+ |
+ typedef_int_t {aka int}
+ { dg-end-multiline-output "" } */
+ /* { dg-begin-multiline-output "" }
+ takes_int_ptr (typedef_int_t_var);
+ ^~~~~~~~~~~~~~~~~
+ &
+ { dg-end-multiline-output "" } */
+ /* { dg-begin-multiline-output "" }
+ void takes_int_ptr(int*);
+ ^~~~
+ { dg-end-multiline-output "" } */
+}