This patch adds a fix-it hint to various pointer-vs-non-pointer diagnostics, suggesting the addition of a leading '&' or '*'.
For example, note the ampersand fix-it hint in the following: demo.c:5:22: error: invalid conversion from 'pthread_key_t' {aka 'unsigned int'} to 'pthread_key_t*' {aka 'unsigned int*'} [-fpermissive] 5 | pthread_key_create(key, NULL); | ^~~ | | | pthread_key_t {aka unsigned int} | & In file included from demo.c:1: /usr/include/pthread.h:1122:47: note: initializing argument 1 of 'int pthread_key_create(pthread_key_t*, void (*)(void*))' 1122 | extern int pthread_key_create (pthread_key_t *__key, | ~~~~~~~~~~~~~~~^~~~~ Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu. OK for trunk? gcc/c-family/ChangeLog: PR c++/87850 * c-common.c (maybe_add_indirection_token): New function. * c-common.h (maybe_add_indirection_token): New decl. gcc/c/ChangeLog: PR c++/87850 * c-typeck.c (convert_for_assignment): Call maybe_add_indirection_token for pointer vs non-pointer diagnostics. gcc/cp/ChangeLog: PR c++/87850 * call.c (convert_like_real): Call maybe_add_indirection_token for "invalid conversion" diagnostic. gcc/testsuite/ChangeLog: PR c++/87850 * c-c++-common/indirection-fixits.c: New test. --- gcc/c-family/c-common.c | 25 +++ gcc/c-family/c-common.h | 2 + gcc/c/c-typeck.c | 2 + gcc/cp/call.c | 1 + gcc/testsuite/c-c++-common/indirection-fixits.c | 250 ++++++++++++++++++++++++ 5 files changed, 280 insertions(+) create mode 100644 gcc/testsuite/c-c++-common/indirection-fixits.c diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 534d928..3756e6d 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -8382,6 +8382,31 @@ maybe_suggest_missing_token_insertion (rich_location *richloc, } } +/* Potentially add a fix-it hint for a missing '&' or '*' to RICHLOC, + depending on EXPR and EXPECTED_TYPE. */ + +void +maybe_add_indirection_token (rich_location *richloc, + tree expr, tree expected_type) +{ + gcc_assert (richloc); + gcc_assert (expr); + gcc_assert (expected_type); + + tree actual_type = TREE_TYPE (expr); + + /* Fix-it hint for missing '&'. */ + if (TREE_CODE (expected_type) == POINTER_TYPE + && actual_type == TREE_TYPE (expected_type) + && lvalue_p (expr)) + richloc->add_fixit_insert_before ("&"); + + /* Fix-it hint for missing '*'. */ + if (TREE_CODE (actual_type) == POINTER_TYPE + && TREE_TYPE (actual_type) == expected_type) + richloc->add_fixit_insert_before ("*"); +} + #if CHECKING_P namespace selftest { diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index a218432..e362137 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -1340,6 +1340,8 @@ 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_add_indirection_token (rich_location *richloc, + tree expr, tree expected_type); extern tree braced_list_to_string (tree, tree); #if CHECKING_P diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index 144977e..f407025 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -7058,6 +7058,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, auto_diagnostic_group d; range_label_for_type_mismatch rhs_label (rhstype, type); gcc_rich_location richloc (expr_loc, &rhs_label); + maybe_add_indirection_token (&richloc, rhs, type); if (pedwarn (&richloc, OPT_Wint_conversion, "passing argument %d of %qE makes pointer from " "integer without a cast", parmnum, rname)) @@ -7094,6 +7095,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, auto_diagnostic_group d; range_label_for_type_mismatch rhs_label (rhstype, type); gcc_rich_location richloc (expr_loc, &rhs_label); + maybe_add_indirection_token (&richloc, rhs, type); if (pedwarn (&richloc, OPT_Wint_conversion, "passing argument %d of %qE makes integer from " "pointer without a cast", parmnum, rname)) diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 6f40156..85d722c 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -6814,6 +6814,7 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum, { range_label_for_type_mismatch label (TREE_TYPE (expr), totype); gcc_rich_location richloc (loc, &label); + maybe_add_indirection_token (&richloc, expr, totype); complained = permerror (&richloc, "invalid conversion from %qH to %qI", TREE_TYPE (expr), totype); diff --git a/gcc/testsuite/c-c++-common/indirection-fixits.c b/gcc/testsuite/c-c++-common/indirection-fixits.c new file mode 100644 index 0000000..2dbd8b2 --- /dev/null +++ b/gcc/testsuite/c-c++-common/indirection-fixits.c @@ -0,0 +1,250 @@ +/* { 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 } */ + + /* Expect an '&' fix-it hint. */ + /* { dg-begin-multiline-output "" } + takes_int_ptr(ivar); + ^~~~ + | + int + & + { 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 "" } + 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 } */ + + /* 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 "" } + 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 } } */ +} + +void test_9 (void) +{ + cvar = 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 "" } + 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 } } */ +} + +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 "" } */ +} -- 1.8.5.3