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

Reply via email to