On 11/9/18, David Malcolm <dmalc...@redhat.com> wrote: > 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} > | &
Having both the type and the fixit underneath the caret looks kind of confusing > 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 > >