public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] C/C++: add fix-it hints for missing '&' and '*' (PR c++/87850)
@ 2018-11-09 22:36 David Malcolm
  2018-11-10  7:01 ` Eric Gallager
  0 siblings, 1 reply; 20+ messages in thread
From: David Malcolm @ 2018-11-09 22:36 UTC (permalink / raw)
  To: gcc-patches; +Cc: David Malcolm

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

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH] C/C++: add fix-it hints for missing '&' and '*' (PR c++/87850)
  2018-11-09 22:36 [PATCH] C/C++: add fix-it hints for missing '&' and '*' (PR c++/87850) David Malcolm
@ 2018-11-10  7:01 ` Eric Gallager
  2018-11-11 18:01   ` Martin Sebor
  0 siblings, 1 reply; 20+ messages in thread
From: Eric Gallager @ 2018-11-10  7:01 UTC (permalink / raw)
  To: David Malcolm; +Cc: gcc-patches

On 11/9/18, David Malcolm <dmalcolm@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
>
>

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH] C/C++: add fix-it hints for missing '&' and '*' (PR c++/87850)
  2018-11-10  7:01 ` Eric Gallager
@ 2018-11-11 18:01   ` Martin Sebor
  2018-11-11 21:02     ` David Malcolm
  0 siblings, 1 reply; 20+ messages in thread
From: Martin Sebor @ 2018-11-11 18:01 UTC (permalink / raw)
  To: Eric Gallager, David Malcolm; +Cc: gcc-patches

On 11/10/2018 12:01 AM, Eric Gallager wrote:
> On 11/9/18, David Malcolm <dmalcolm@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

I agree it's rather subtle.  Keeping the diagnostics separate from
the suggested fix should avoid the confusion.

Martin

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH] C/C++: add fix-it hints for missing '&' and '*' (PR c++/87850)
  2018-11-11 18:01   ` Martin Sebor
@ 2018-11-11 21:02     ` David Malcolm
  2018-11-12 21:32       ` Martin Sebor
  0 siblings, 1 reply; 20+ messages in thread
From: David Malcolm @ 2018-11-11 21:02 UTC (permalink / raw)
  To: Martin Sebor, Eric Gallager; +Cc: gcc-patches

On Sun, 2018-11-11 at 11:01 -0700, Martin Sebor wrote:
> On 11/10/2018 12:01 AM, Eric Gallager wrote:
> > On 11/9/18, David Malcolm <dmalcolm@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
> 
> I agree it's rather subtle.  Keeping the diagnostics separate from
> the suggested fix should avoid the confusion.

FWIW, the fix-it hint is in a different color (assuming that gcc is
invoked in an environment that prints that...)

Dave

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH] C/C++: add fix-it hints for missing '&' and '*' (PR c++/87850)
  2018-11-11 21:02     ` David Malcolm
@ 2018-11-12 21:32       ` Martin Sebor
  2018-11-13 21:34         ` Jason Merrill
  0 siblings, 1 reply; 20+ messages in thread
From: Martin Sebor @ 2018-11-12 21:32 UTC (permalink / raw)
  To: David Malcolm, Eric Gallager; +Cc: gcc-patches

On 11/11/2018 02:02 PM, David Malcolm wrote:
> On Sun, 2018-11-11 at 11:01 -0700, Martin Sebor wrote:
>> On 11/10/2018 12:01 AM, Eric Gallager wrote:
>>> On 11/9/18, David Malcolm <dmalcolm@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
>>
>> I agree it's rather subtle.  Keeping the diagnostics separate from
>> the suggested fix should avoid the confusion.
>
> FWIW, the fix-it hint is in a different color (assuming that gcc is
> invoked in an environment that prints that...)

I figured it would be, but I'm still not sure it's good design
to be relying on color alone to distinguish between the problem
and the suggested fix.  Especially when they are so close to one
another and the fix is just a single character with no obvious
relationship to the rest of the text on the screen.  In other
warnings there's at least the "did you forget the '@'?" part
to give a clue, even though even there the connection between
the "did you forget" and the & several lines down wouldn't
necessarily be immediately apparent.

I'm not an expert on these things so I'm going strictly by
intuition and my personal bias.  Are there any user interface
guidelines that you like to refer to that speak to this?  (Other
than our own or the blog post you referenced in one of your posts.)

Back in my GUI days, I remember reading articles and even whole
books on how to design good interfaces, including layouts and
the use of color (e.g., for the color-blind).  It seems like
there should be something relevant for the command line as well,
at least some basic principles that we could apply.

Martin

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH] C/C++: add fix-it hints for missing '&' and '*' (PR c++/87850)
  2018-11-12 21:32       ` Martin Sebor
@ 2018-11-13 21:34         ` Jason Merrill
  2018-11-15 21:48           ` [PATCH] v2: " David Malcolm
  0 siblings, 1 reply; 20+ messages in thread
From: Jason Merrill @ 2018-11-13 21:34 UTC (permalink / raw)
  To: Martin Sebor; +Cc: David Malcolm, Eric Gallager, gcc-patches List

On Mon, Nov 12, 2018 at 4:32 PM Martin Sebor <msebor@gmail.com> wrote:
> On 11/11/2018 02:02 PM, David Malcolm wrote:
> > On Sun, 2018-11-11 at 11:01 -0700, Martin Sebor wrote:
> >> On 11/10/2018 12:01 AM, Eric Gallager wrote:
> >>> On 11/9/18, David Malcolm <dmalcolm@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
> >>
> >> I agree it's rather subtle.  Keeping the diagnostics separate from
> >> the suggested fix should avoid the confusion.
> >
> > FWIW, the fix-it hint is in a different color (assuming that gcc is
> > invoked in an environment that prints that...)
>
> I figured it would be, but I'm still not sure it's good design
> to be relying on color alone to distinguish between the problem
> and the suggested fix.  Especially when they are so close to one
> another and the fix is just a single character with no obvious
> relationship to the rest of the text on the screen.  In other
> warnings there's at least the "did you forget the '@'?" part
> to give a clue, even though even there the connection between
> the "did you forget" and the & several lines down wouldn't
> necessarily be immediately apparent.

Agreed, something along those lines would help to understand why the
compiler is throwing a random & into the diagnostic.

Jason

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH] v2: C/C++: add fix-it hints for missing '&' and '*' (PR c++/87850)
  2018-11-13 21:34         ` Jason Merrill
@ 2018-11-15 21:48           ` David Malcolm
  2018-11-16 18:13             ` Jason Merrill
  0 siblings, 1 reply; 20+ messages in thread
From: David Malcolm @ 2018-11-15 21:48 UTC (permalink / raw)
  To: Jason Merrill
  Cc: Martin Sebor, Eric Gallager, gcc-patches List, David Malcolm

On Tue, 2018-11-13 at 16:34 -0500, Jason Merrill wrote:
> On Mon, Nov 12, 2018 at 4:32 PM Martin Sebor <msebor@gmail.com>
> wrote:
> > On 11/11/2018 02:02 PM, David Malcolm wrote:
> > > On Sun, 2018-11-11 at 11:01 -0700, Martin Sebor wrote:
> > > > On 11/10/2018 12:01 AM, Eric Gallager wrote:
> > > > > On 11/9/18, David Malcolm <dmalcolm@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
> > > > 
> > > > I agree it's rather subtle.  Keeping the diagnostics separate
> > > > from
> > > > the suggested fix should avoid the confusion.
> > > 
> > > FWIW, the fix-it hint is in a different color (assuming that gcc
> > > is
> > > invoked in an environment that prints that...)
> > 
> > I figured it would be, but I'm still not sure it's good design
> > to be relying on color alone to distinguish between the problem
> > and the suggested fix.  Especially when they are so close to one
> > another and the fix is just a single character with no obvious
> > relationship to the rest of the text on the screen.  In other
> > warnings there's at least the "did you forget the '@'?" part
> > to give a clue, even though even there the connection between
> > the "did you forget" and the & several lines down wouldn't
> > necessarily be immediately apparent.
> 
> Agreed, something along those lines would help to understand why the
> compiler is throwing a random & into the diagnostic.
> 
> Jason

Here's an updated version which adds a note, putting the fix-it hint
on that instead (I attempted adding the text to the initial error,
but there was something of a combinatorial explosion of messages).

The above example becomes:

demo.c: In function 'int main()':
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}
demo.c:5:22: note: possible fix: take the address with '&'
    5 |   pthread_key_create(key, NULL);
      |                      ^~~
      |                      &
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: Include "gcc-rich-location.h".
	(maybe_emit_indirection_note): New function.
	* c-common.h (maybe_emit_indirection_note): New decl.

gcc/c/ChangeLog:
	PR c++/87850
	* c-typeck.c (convert_for_assignment): Call
	maybe_emit_indirection_note for pointer vs non-pointer
	diagnostics.

gcc/cp/ChangeLog:
	PR c++/87850
	* call.c (convert_like_real): Call
	maybe_emit_indirection_note for "invalid conversion" diagnostic.

gcc/testsuite/ChangeLog:
	PR c++/87850
	* c-c++-common/indirection-fixits.c: New test.
---
 gcc/c-family/c-common.c                         |  33 +++
 gcc/c-family/c-common.h                         |   2 +
 gcc/c/c-typeck.c                                |  10 +-
 gcc/cp/call.c                                   |   2 +
 gcc/testsuite/c-c++-common/indirection-fixits.c | 270 ++++++++++++++++++++++++
 5 files changed, 315 insertions(+), 2 deletions(-)
 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 cd88f3a..d5c7c7f 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -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
+      && 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
+      && 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 {
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 31cc273..e765d3c 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_emit_indirection_note (location_t loc,
+					 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 5d4e973..efa836d 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -7061,7 +7061,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 +7100,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:
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index ee099cc..a25d109 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -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),
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..4e45d66
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/indirection-fixits.c
@@ -0,0 +1,270 @@
+/* { 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 "" } */
+}
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH] v2: C/C++: add fix-it hints for missing '&' and '*' (PR c++/87850)
  2018-11-15 21:48           ` [PATCH] v2: " David Malcolm
@ 2018-11-16 18:13             ` Jason Merrill
  2018-11-19 21:23               ` [PATCH] v3: " David Malcolm
  0 siblings, 1 reply; 20+ messages in thread
From: Jason Merrill @ 2018-11-16 18:13 UTC (permalink / raw)
  To: David Malcolm; +Cc: Martin Sebor, Eric Gallager, gcc-patches List

On Thu, Nov 15, 2018 at 4:48 PM David Malcolm <dmalcolm@redhat.com> wrote:
> On Tue, 2018-11-13 at 16:34 -0500, Jason Merrill wrote:
> > On Mon, Nov 12, 2018 at 4:32 PM Martin Sebor <msebor@gmail.com>
> > wrote:
> > > On 11/11/2018 02:02 PM, David Malcolm wrote:
> > > > On Sun, 2018-11-11 at 11:01 -0700, Martin Sebor wrote:
> > > > > On 11/10/2018 12:01 AM, Eric Gallager wrote:
> > > > > > On 11/9/18, David Malcolm <dmalcolm@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
> > > > >
> > > > > I agree it's rather subtle.  Keeping the diagnostics separate
> > > > > from
> > > > > the suggested fix should avoid the confusion.
> > > >
> > > > FWIW, the fix-it hint is in a different color (assuming that gcc
> > > > is
> > > > invoked in an environment that prints that...)
> > >
> > > I figured it would be, but I'm still not sure it's good design
> > > to be relying on color alone to distinguish between the problem
> > > and the suggested fix.  Especially when they are so close to one
> > > another and the fix is just a single character with no obvious
> > > relationship to the rest of the text on the screen.  In other
> > > warnings there's at least the "did you forget the '@'?" part
> > > to give a clue, even though even there the connection between
> > > the "did you forget" and the & several lines down wouldn't
> > > necessarily be immediately apparent.
> >
> > Agreed, something along those lines would help to understand why the
> > compiler is throwing a random & into the diagnostic.
> >
> > Jason
>
> Here's an updated version which adds a note, putting the fix-it hint
> on that instead (I attempted adding the text to the initial error,
> but there was something of a combinatorial explosion of messages).
>
> The above example becomes:
>
> demo.c: In function 'int main()':
> 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}
> demo.c:5:22: note: possible fix: take the address with '&'
>     5 |   pthread_key_create(key, NULL);
>       |                      ^~~
>       |                      &
> 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: Include "gcc-rich-location.h".
>         (maybe_emit_indirection_note): New function.
>         * c-common.h (maybe_emit_indirection_note): New decl.
>
> gcc/c/ChangeLog:
>         PR c++/87850
>         * c-typeck.c (convert_for_assignment): Call
>         maybe_emit_indirection_note for pointer vs non-pointer
>         diagnostics.
>
> gcc/cp/ChangeLog:
>         PR c++/87850
>         * call.c (convert_like_real): Call
>         maybe_emit_indirection_note for "invalid conversion" diagnostic.
>
> gcc/testsuite/ChangeLog:
>         PR c++/87850
>         * c-c++-common/indirection-fixits.c: New test.
> ---
>  gcc/c-family/c-common.c                         |  33 +++
>  gcc/c-family/c-common.h                         |   2 +
>  gcc/c/c-typeck.c                                |  10 +-
>  gcc/cp/call.c                                   |   2 +
>  gcc/testsuite/c-c++-common/indirection-fixits.c | 270 ++++++++++++++++++++++++
>  5 files changed, 315 insertions(+), 2 deletions(-)
>  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 cd88f3a..d5c7c7f 100644
> --- a/gcc/c-family/c-common.c
> +++ b/gcc/c-family/c-common.c
> @@ -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
> +      && actual_type == TREE_TYPE (expected_type)

Type comparison should use same_type_p, not ==, so that we deal
properly with typedef variants.  OK with that change.

Jason

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH] v3: C/C++: add fix-it hints for missing '&' and '*' (PR c++/87850)
  2018-11-16 18:13             ` Jason Merrill
@ 2018-11-19 21:23               ` David Malcolm
  2018-11-20  2:46                 ` Joseph Myers
                                   ` (2 more replies)
  0 siblings, 3 replies; 20+ messages in thread
From: David Malcolm @ 2018-11-19 21:23 UTC (permalink / raw)
  To: Jason Merrill
  Cc: Martin Sebor, Eric Gallager, gcc-patches List, David Malcolm

On Fri, 2018-11-16 at 13:13 -0500, Jason Merrill wrote:
> On Thu, Nov 15, 2018 at 4:48 PM David Malcolm <dmalcolm@redhat.com>
> wrote:
> > On Tue, 2018-11-13 at 16:34 -0500, Jason Merrill wrote:
> > > On Mon, Nov 12, 2018 at 4:32 PM Martin Sebor <msebor@gmail.com>
> > > wrote:
> > > > On 11/11/2018 02:02 PM, David Malcolm wrote:
> > > > > On Sun, 2018-11-11 at 11:01 -0700, Martin Sebor wrote:
> > > > > > On 11/10/2018 12:01 AM, Eric Gallager wrote:
> > > > > > > On 11/9/18, David Malcolm <dmalcolm@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
> > > > > > 
> > > > > > I agree it's rather subtle.  Keeping the diagnostics
> > > > > > separate
> > > > > > from
> > > > > > the suggested fix should avoid the confusion.
> > > > > 
> > > > > FWIW, the fix-it hint is in a different color (assuming that
> > > > > gcc
> > > > > is
> > > > > invoked in an environment that prints that...)
> > > > 
> > > > I figured it would be, but I'm still not sure it's good design
> > > > to be relying on color alone to distinguish between the problem
> > > > and the suggested fix.  Especially when they are so close to
> > > > one
> > > > another and the fix is just a single character with no obvious
> > > > relationship to the rest of the text on the screen.  In other
> > > > warnings there's at least the "did you forget the '@'?" part
> > > > to give a clue, even though even there the connection between
> > > > the "did you forget" and the & several lines down wouldn't
> > > > necessarily be immediately apparent.
> > > 
> > > Agreed, something along those lines would help to understand why
> > > the
> > > compiler is throwing a random & into the diagnostic.
> > > 
> > > Jason
> > 
> > Here's an updated version which adds a note, putting the fix-it
> > hint
> > on that instead (I attempted adding the text to the initial error,
> > but there was something of a combinatorial explosion of messages).
> > 
> > The above example becomes:
> > 
> > demo.c: In function 'int main()':
> > 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}
> > demo.c:5:22: note: possible fix: take the address with '&'
> >     5 |   pthread_key_create(key, NULL);
> >       |                      ^~~
> >       |                      &
> > 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: Include "gcc-rich-location.h".
> >         (maybe_emit_indirection_note): New function.
> >         * c-common.h (maybe_emit_indirection_note): New decl.
> > 
> > gcc/c/ChangeLog:
> >         PR c++/87850
> >         * c-typeck.c (convert_for_assignment): Call
> >         maybe_emit_indirection_note for pointer vs non-pointer
> >         diagnostics.
> > 
> > gcc/cp/ChangeLog:
> >         PR c++/87850
> >         * call.c (convert_like_real): Call
> >         maybe_emit_indirection_note for "invalid conversion"
> > diagnostic.
> > 
> > gcc/testsuite/ChangeLog:
> >         PR c++/87850
> >         * c-c++-common/indirection-fixits.c: New test.
> > ---
> >  gcc/c-family/c-common.c                         |  33 +++
> >  gcc/c-family/c-common.h                         |   2 +
> >  gcc/c/c-typeck.c                                |  10 +-
> >  gcc/cp/call.c                                   |   2 +
> >  gcc/testsuite/c-c++-common/indirection-fixits.c | 270
> > ++++++++++++++++++++++++
> >  5 files changed, 315 insertions(+), 2 deletions(-)
> >  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 cd88f3a..d5c7c7f 100644
> > --- a/gcc/c-family/c-common.c
> > +++ b/gcc/c-family/c-common.c
> > @@ -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
> > +      && actual_type == TREE_TYPE (expected_type)
> 
> Type comparison should use same_type_p, not ==, so that we deal
> properly with typedef variants.  OK with that change.
> 
> Jason

The above code is in c-family, but same_type_p is specific to C++,
so the change is not quite trivial.

Here's a v3 of the patch which moves same_type_p from cp/cp-tree.h
to c-family/c-common.h, converting it from a macro to an extern decl,
with implementations for C and for C++.  I used:
  comptypes (type1, type2) == 1
for the C implementation of same_type_p.

The v3 patch uses same_type_p rather than pointer equality, and I added
a test case for a typedef of int vs a int.

Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.

Is this OK for trunk?

Thanks
Dave

gcc/c-family/ChangeLog:
	PR c++/87850
	* c-common.c: Include "gcc-rich-location.h".
	(maybe_emit_indirection_note): New function.
	* c-common.h (maybe_emit_indirection_note): New decl.
	(same_type_p): New decl

gcc/c/ChangeLog:
	PR c++/87850
	* c-typeck.c (same_type_p): New function.
	(convert_for_assignment): Call maybe_emit_indirection_note for
	pointer vs non-pointer diagnostics.

gcc/cp/ChangeLog:
	PR c++/87850
	* call.c (convert_like_real): Call
	maybe_emit_indirection_note for "invalid conversion" diagnostic.
	* cp-tree.h (same_type_p): Delete macro, moving to...
	* typeck.c (same_type_p): New function.

gcc/testsuite/ChangeLog:
	PR c++/87850
	* c-c++-common/indirection-fixits.c: New test.
---
 gcc/c-family/c-common.c                         |  33 +++
 gcc/c-family/c-common.h                         |   4 +
 gcc/c/c-typeck.c                                |  20 +-
 gcc/cp/call.c                                   |   2 +
 gcc/cp/cp-tree.h                                |   5 -
 gcc/cp/typeck.c                                 |  10 +
 gcc/testsuite/c-c++-common/indirection-fixits.c | 299 ++++++++++++++++++++++++
 7 files changed, 366 insertions(+), 7 deletions(-)
 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 cd88f3a..babe329 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -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 {
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 31cc273..e0be104 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -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,
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 5d4e973..1ddcf71 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -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:
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index ee099cc..a25d109 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -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),
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index f2e6709..57d9eed 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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)				\
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 7b42d53..eeae9f1 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -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.  */
 
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..8987ee9
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/indirection-fixits.c
@@ -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 "" } */
+}
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH] v3: C/C++: add fix-it hints for missing '&' and '*' (PR c++/87850)
  2018-11-19 21:23               ` [PATCH] v3: " David Malcolm
@ 2018-11-20  2:46                 ` Joseph Myers
  2018-11-20 22:05                   ` David Malcolm
  2018-11-21  0:36                 ` [PATCH] v3: " Jeff Law
  2018-11-21  0:39                 ` Martin Sebor
  2 siblings, 1 reply; 20+ messages in thread
From: Joseph Myers @ 2018-11-20  2:46 UTC (permalink / raw)
  To: David Malcolm
  Cc: Jason Merrill, Martin Sebor, Eric Gallager, gcc-patches List

On Mon, 19 Nov 2018, David Malcolm wrote:

> +/* 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;
> +}

I don't think "compatible" and "same" are the same concept.  Normally in C 
you'd be concerned with compatibility; "same type" is only used for the 
rule on duplicate typedefs, which uses comptypes_check_different_types.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH] v3: C/C++: add fix-it hints for missing '&' and '*' (PR c++/87850)
  2018-11-20  2:46                 ` Joseph Myers
@ 2018-11-20 22:05                   ` David Malcolm
  2018-11-20 22:23                     ` Joseph Myers
  0 siblings, 1 reply; 20+ messages in thread
From: David Malcolm @ 2018-11-20 22:05 UTC (permalink / raw)
  To: Joseph Myers; +Cc: Jason Merrill, Martin Sebor, Eric Gallager, gcc-patches List

On Tue, 2018-11-20 at 02:46 +0000, Joseph Myers wrote:
> On Mon, 19 Nov 2018, David Malcolm wrote:
> 
> > +/* 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;
> > +}
> 
> I don't think "compatible" and "same" are the same concept.  Normally
> in C 
> you'd be concerned with compatibility; "same type" is only used for
> the 
> rule on duplicate typedefs, which uses
> comptypes_check_different_types.

The purpose here is to be able to offer fix-it hints for bogus code
that's missing an '&' or a '*' prefix, and have that code live in c-
common.c

Jason wanted to avoid a pointer-equality test for types by using
same_type_p to look through enums - but same_type_p is C++-specific.

Should I do:

(a) something like this for C:

/* C implementation of same_type_p.
   Returns true iff TYPE1 and TYPE2 are the same type, or are
   compatible enough to be permitted in C11 typedef redeclarations.  */

bool
same_type_p (tree type1, tree type2)
{
  bool different_types_p = false;
  int result = comptypes_check_different_types (type1, type2,
						&different_types_p);

  if (result == 1 && !different_types_p)
    return true;

  return false;   
}

(b) provide a same_type_p for C that e.g. simply does pointer equality,

(d) add a newly named function (e.g. "compatible_types_p", as C++ has a
comptypes, but it has a 3rd param), or

(d) fall back to simply doing pointer equality.


Thanks
Dave

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH] v3: C/C++: add fix-it hints for missing '&' and '*' (PR c++/87850)
  2018-11-20 22:05                   ` David Malcolm
@ 2018-11-20 22:23                     ` Joseph Myers
  2018-11-30 23:01                       ` [PATCH] v4: " David Malcolm
  0 siblings, 1 reply; 20+ messages in thread
From: Joseph Myers @ 2018-11-20 22:23 UTC (permalink / raw)
  To: David Malcolm
  Cc: Jason Merrill, Martin Sebor, Eric Gallager, gcc-patches List

On Tue, 20 Nov 2018, David Malcolm wrote:

> Should I do:

You should do whatever is appropriate for the warning in question.  But if 
what's appropriate for the warning in question includes types that are 
compatible but not the same, the comments need to avoid saying it's about 
the types being the same.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH] v3: C/C++: add fix-it hints for missing '&' and '*' (PR c++/87850)
  2018-11-19 21:23               ` [PATCH] v3: " David Malcolm
  2018-11-20  2:46                 ` Joseph Myers
@ 2018-11-21  0:36                 ` Jeff Law
  2018-11-21  0:39                 ` Martin Sebor
  2 siblings, 0 replies; 20+ messages in thread
From: Jeff Law @ 2018-11-21  0:36 UTC (permalink / raw)
  To: David Malcolm, Jason Merrill
  Cc: Martin Sebor, Eric Gallager, gcc-patches List

On 11/19/18 2:23 PM, David Malcolm wrote:
[ Snip ]

> 
> The above code is in c-family, but same_type_p is specific to C++,
> so the change is not quite trivial.
> 
> Here's a v3 of the patch which moves same_type_p from cp/cp-tree.h
> to c-family/c-common.h, converting it from a macro to an extern decl,
> with implementations for C and for C++.  I used:
>   comptypes (type1, type2) == 1
> for the C implementation of same_type_p.
> 
> The v3 patch uses same_type_p rather than pointer equality, and I added
> a test case for a typedef of int vs a int.
> 
> Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.
> 
> Is this OK for trunk?
> 
> Thanks
> Dave
> 
> gcc/c-family/ChangeLog:
> 	PR c++/87850
> 	* c-common.c: Include "gcc-rich-location.h".
> 	(maybe_emit_indirection_note): New function.
> 	* c-common.h (maybe_emit_indirection_note): New decl.
> 	(same_type_p): New decl
> 
> gcc/c/ChangeLog:
> 	PR c++/87850
> 	* c-typeck.c (same_type_p): New function.
> 	(convert_for_assignment): Call maybe_emit_indirection_note for
> 	pointer vs non-pointer diagnostics.
> 
> gcc/cp/ChangeLog:
> 	PR c++/87850
> 	* call.c (convert_like_real): Call
> 	maybe_emit_indirection_note for "invalid conversion" diagnostic.
> 	* cp-tree.h (same_type_p): Delete macro, moving to...
> 	* typeck.c (same_type_p): New function.
> 
> gcc/testsuite/ChangeLog:
> 	PR c++/87850
> 	* c-c++-common/indirection-fixits.c: New test.
OK.
jeff

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH] v3: C/C++: add fix-it hints for missing '&' and '*' (PR c++/87850)
  2018-11-19 21:23               ` [PATCH] v3: " David Malcolm
  2018-11-20  2:46                 ` Joseph Myers
  2018-11-21  0:36                 ` [PATCH] v3: " Jeff Law
@ 2018-11-21  0:39                 ` Martin Sebor
  2018-11-30 15:27                   ` David Malcolm
  2 siblings, 1 reply; 20+ messages in thread
From: Martin Sebor @ 2018-11-21  0:39 UTC (permalink / raw)
  To: David Malcolm, Jason Merrill; +Cc: Eric Gallager, gcc-patches List

> +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);
> +                 ^~~~
> +                 &

I experimented with adding hints to sizeof_pointer_memaccess_warning
over the weekend and ran into a location difference between the two
front-ends.  In an attempt to resolve it, rather than using
an "insertion hint" like I think you did above, I used a replacement
hint.  And although it started out as a workaround I ended up liking
the result better.  What I think the same approach would result in
here is something like:

   takes_int_ptr(ivar);
   note: possible fix: take the address with '&'
   note: takes_int_ptr(ivar);
                       ^~~~
                       |
                       int
    note: takes_int_ptr(ivar);
                        ^~~~
                        &ivar

Have you considered this style, i.e., printing valid expressions
in the hints when possible rather than just operators?  It solves
the problem of the lone operators looking a little too terse and
cryptic.

I realize it's not always possible (not every fix-it hint is for
a bad expression) but I'm wondering if it would be worth using
when it is.

Martin

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH] v3: C/C++: add fix-it hints for missing '&' and '*' (PR c++/87850)
  2018-11-21  0:39                 ` Martin Sebor
@ 2018-11-30 15:27                   ` David Malcolm
  0 siblings, 0 replies; 20+ messages in thread
From: David Malcolm @ 2018-11-30 15:27 UTC (permalink / raw)
  To: Martin Sebor, Jason Merrill; +Cc: Eric Gallager, gcc-patches List

On Tue, 2018-11-20 at 17:39 -0700, Martin Sebor wrote:
> > +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);
> > +                 ^~~~
> > +                 &
> 
> I experimented with adding hints to sizeof_pointer_memaccess_warning
> over the weekend and ran into a location difference between the two
> front-ends.  In an attempt to resolve it, rather than using
> an "insertion hint" like I think you did above, I used a replacement
> hint.  And although it started out as a workaround I ended up liking
> the result better.  What I think the same approach would result in
> here is something like:
> 
>    takes_int_ptr(ivar);
>    note: possible fix: take the address with '&'
>    note: takes_int_ptr(ivar);
>                        ^~~~
>                        |
>                        int
>     note: takes_int_ptr(ivar);
>                         ^~~~
>                         &ivar
> 
> Have you considered this style, i.e., printing valid expressions
> in the hints when possible rather than just operators?  It solves
> the problem of the lone operators looking a little too terse and
> cryptic.
> 
> I realize it's not always possible (not every fix-it hint is for
> a bad expression) but I'm wondering if it would be worth using
> when it is.

I definitely prefer the style of the output in your example, but I
think there's a "data model vs presentation" thing going on here.

I'd prefer to avoid the underlying rich_location using replacement when
we mean insertion, for the same reasons as for deletion discussed at
[1]

I think the issue here is with the presentation of insertion fix-it
hints in diagnostic-show-locus.c: there's currently no way for the user
to tell if this:

  takes_int_ptr(ivar);
                ^~~~
                &

means:
  (a) replace "ivar" with "&", or
  (b) insert "&" in front of "ivar" (the intended behavior)

and this alternative presentation would definitely be clearer:

  takes_int_ptr(ivar);
                ^~~~
                &ivar

I can have a look at reimplementing how we present insertions in
diagnostic-show-locus.c.

Dave

[1] https://gcc.gnu.org/onlinedocs/gccint/Guidelines-for-Diagnostics.html#Express-deletion-in-terms-of-deletion_002c-not-replacement

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH] v4: C/C++: add fix-it hints for missing '&' and '*' (PR c++/87850)
  2018-11-20 22:23                     ` Joseph Myers
@ 2018-11-30 23:01                       ` David Malcolm
  2018-12-01 18:38                         ` Jason Merrill
  0 siblings, 1 reply; 20+ messages in thread
From: David Malcolm @ 2018-11-30 23:01 UTC (permalink / raw)
  To: Joseph Myers, Jason Merrill, law
  Cc: Martin Sebor, Eric Gallager, gcc-patches List, David Malcolm

On Tue, 2018-11-20 at 22:23 +0000, Joseph Myers wrote:
> On Tue, 20 Nov 2018, David Malcolm wrote:
> 
> > Should I do:
> 
> You should do whatever is appropriate for the warning in
> question.  But if 
> what's appropriate for the warning in question includes types that
> are 
> compatible but not the same, the comments need to avoid saying it's
> about 
> the types being the same. 

Thanks.

Here's an updated version of the patch.  I added a new
  compatible_types_for_indirection_note_p
specifically for use by maybe_emit_indirection_note, and provided
implementations for C and C++.

Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.

OK for trunk?


Changed in v4: introduce a compatible_types_for_indirection_note_p
function, and use it in place of same_type_p.

Changed in v3: use same_type_p rather than pointer equality.
Provide implementation of same_type_p for C.

Changed in v2: add a note, and put the fix-it hint on that instead

Blurb follows:

This patch adds a note with 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: In function 'int main()':
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}
demo.c:5:22: note: possible fix: take the address with '&'
    5 |   pthread_key_create(key, NULL);
      |                      ^~~
      |                      &
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,
      |                                ~~~~~~~~~~~~~~~^~~~~

gcc/c-family/ChangeLog:
	PR c++/87850
	* c-common.c: Include "gcc-rich-location.h".
	(maybe_emit_indirection_note): New function.
	* c-common.h (maybe_emit_indirection_note): New decl.
	(compatible_types_for_indirection_note_p): New decl.

gcc/c/ChangeLog:
	PR c++/87850
	* c-typeck.c (compatible_types_for_indirection_note_p): New
	function.
	(convert_for_assignment): Call maybe_emit_indirection_note for
	pointer vs non-pointer diagnostics.

gcc/cp/ChangeLog:
	PR c++/87850
	* call.c (convert_like_real): Call
	maybe_emit_indirection_note for "invalid conversion" diagnostic.
	* typeck.c (compatible_types_for_indirection_note_p): New
	function.

gcc/testsuite/ChangeLog:
	PR c++/87850
	* c-c++-common/indirection-fixits.c: New test.
---
 gcc/c-family/c-common.c                         |  35 +++
 gcc/c-family/c-common.h                         |   4 +
 gcc/c/c-typeck.c                                |  18 +-
 gcc/cp/call.c                                   |   2 +
 gcc/cp/typeck.c                                 |   8 +
 gcc/testsuite/c-c++-common/indirection-fixits.c | 299 ++++++++++++++++++++++++
 6 files changed, 364 insertions(+), 2 deletions(-)
 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 9d51815..f235c9d 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -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.  */
@@ -8420,6 +8421,40 @@ 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
+      && compatible_types_for_indirection_note_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
+      && compatible_types_for_indirection_note_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 {
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 4187343..0b1fdd7 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -1355,6 +1355,10 @@ 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 bool compatible_types_for_indirection_note_p (tree type1, tree type2);
+
 extern tree braced_list_to_string (tree, tree);
 extern bool has_attribute (location_t, tree, tree, tree (*)(tree));
 
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 81c520a..cb7184b 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -1004,6 +1004,14 @@ common_type (tree t1, tree t2)
   return c_common_type (t1, t2);
 }
 
+/* C implementation of compatible_types_for_indirection_note_p.  */
+
+bool
+compatible_types_for_indirection_note_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.  */
@@ -7293,7 +7301,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:
@@ -7329,7 +7340,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:
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index ee099cc..a25d109 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -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),
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 81cb405..2730f77 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -1448,6 +1448,14 @@ structural_comptypes (tree t1, tree t2, int strict)
   return comp_type_attributes (t1, t2);
 }
 
+/* C++ implementation of compatible_types_for_indirection_note_p.  */
+
+bool
+compatible_types_for_indirection_note_p (tree type1, tree type2)
+{
+  return same_type_p (type1, type2);
+}
+
 /* Return true if T1 and T2 are related as allowed by STRICT.  STRICT
    is a bitwise-or of the COMPARE_* flags.  */
 
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..8987ee9
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/indirection-fixits.c
@@ -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 "" } */
+}
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH] v4: C/C++: add fix-it hints for missing '&' and '*' (PR c++/87850)
  2018-11-30 23:01                       ` [PATCH] v4: " David Malcolm
@ 2018-12-01 18:38                         ` Jason Merrill
  2018-12-03 22:14                           ` Joseph Myers
  0 siblings, 1 reply; 20+ messages in thread
From: Jason Merrill @ 2018-12-01 18:38 UTC (permalink / raw)
  To: David Malcolm, Joseph Myers, law
  Cc: Martin Sebor, Eric Gallager, gcc-patches List

On 11/30/18 6:48 PM, David Malcolm wrote:
> On Tue, 2018-11-20 at 22:23 +0000, Joseph Myers wrote:
>> On Tue, 20 Nov 2018, David Malcolm wrote:
>>
>>> Should I do:
>>
>> You should do whatever is appropriate for the warning in question.  But if
>> what's appropriate for the warning in question includes types that are
>> compatible but not the same, the comments need to avoid saying it's about
>> the types being the same.

> Thanks.
> 
> Here's an updated version of the patch.  I added a new
>    compatible_types_for_indirection_note_p
> specifically for use by maybe_emit_indirection_note, and provided
> implementations for C and C++.

> +/* C implementation of compatible_types_for_indirection_note_p.  */
> +
> +bool
> +compatible_types_for_indirection_note_p (tree type1, tree type2)
> +{
> +  return comptypes (type1, type2) == 1;
> +}

Hmm, it looks like the C front-end comptypes will return 1 for e.g. enum 
and int.  It seems to me that what you want for this warning is actually 
to check for the same type.  Perhaps you want to use 
comptypes_check_different_types?  Joseph would know better what's 
correct for the C front-end.

Jason

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH] v4: C/C++: add fix-it hints for missing '&' and '*' (PR c++/87850)
  2018-12-01 18:38                         ` Jason Merrill
@ 2018-12-03 22:14                           ` Joseph Myers
  2018-12-05 16:03                             ` Jason Merrill
  0 siblings, 1 reply; 20+ messages in thread
From: Joseph Myers @ 2018-12-03 22:14 UTC (permalink / raw)
  To: Jason Merrill
  Cc: David Malcolm, law, Martin Sebor, Eric Gallager, gcc-patches List

On Sat, 1 Dec 2018, Jason Merrill wrote:

> Hmm, it looks like the C front-end comptypes will return 1 for e.g. enum and
> int.  It seems to me that what you want for this warning is actually to check
> for the same type.  Perhaps you want to use comptypes_check_different_types?
> Joseph would know better what's correct for the C front-end.

Well, it's valid to pass a pointer to enum where a pointer to the 
compatible integer type is required, or vice versa, but I don't have 
advice on which cases you want to accept for this particular fix-it.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH] v4: C/C++: add fix-it hints for missing '&' and '*' (PR c++/87850)
  2018-12-03 22:14                           ` Joseph Myers
@ 2018-12-05 16:03                             ` Jason Merrill
  2018-12-05 16:18                               ` David Malcolm
  0 siblings, 1 reply; 20+ messages in thread
From: Jason Merrill @ 2018-12-05 16:03 UTC (permalink / raw)
  To: Joseph S. Myers
  Cc: David Malcolm, Jeff Law, Martin Sebor, Eric Gallager, gcc-patches List

On Mon, Dec 3, 2018 at 5:14 PM Joseph Myers <joseph@codesourcery.com> wrote:
>
> On Sat, 1 Dec 2018, Jason Merrill wrote:
>
> > Hmm, it looks like the C front-end comptypes will return 1 for e.g. enum and
> > int.  It seems to me that what you want for this warning is actually to check
> > for the same type.  Perhaps you want to use comptypes_check_different_types?
> > Joseph would know better what's correct for the C front-end.
>
> Well, it's valid to pass a pointer to enum where a pointer to the
> compatible integer type is required, or vice versa, but I don't have
> advice on which cases you want to accept for this particular fix-it.

Since the diagnostic is about returning, e.g. an int when an int* is
needed, or vice versa, I don't think considering that kind of
conversion is helpful.

Jason

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH] v4: C/C++: add fix-it hints for missing '&' and '*' (PR c++/87850)
  2018-12-05 16:03                             ` Jason Merrill
@ 2018-12-05 16:18                               ` David Malcolm
  0 siblings, 0 replies; 20+ messages in thread
From: David Malcolm @ 2018-12-05 16:18 UTC (permalink / raw)
  To: Jason Merrill, Joseph S. Myers
  Cc: Jeff Law, Martin Sebor, Eric Gallager, gcc-patches List

On Wed, 2018-12-05 at 11:03 -0500, Jason Merrill wrote:
> On Mon, Dec 3, 2018 at 5:14 PM Joseph Myers <joseph@codesourcery.com>
> wrote:
> > 
> > On Sat, 1 Dec 2018, Jason Merrill wrote:
> > 
> > > Hmm, it looks like the C front-end comptypes will return 1 for
> > > e.g. enum and
> > > int.  It seems to me that what you want for this warning is
> > > actually to check
> > > for the same type.  Perhaps you want to use
> > > comptypes_check_different_types?
> > > Joseph would know better what's correct for the C front-end.
> > 
> > Well, it's valid to pass a pointer to enum where a pointer to the
> > compatible integer type is required, or vice versa, but I don't
> > have
> > advice on which cases you want to accept for this particular fix-
> > it.
> 
> Since the diagnostic is about returning, e.g. an int when an int* is
> needed, or vice versa, I don't think considering that kind of
> conversion is helpful.

FWIW I'd be happy to use simple pointer equality of the types for the C
FE, so that we only emit the suggestion for an exact match (better to
fail to offer a suggestion than to offer a bogus one, I think).

Dave

^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2018-12-05 16:18 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-11-09 22:36 [PATCH] C/C++: add fix-it hints for missing '&' and '*' (PR c++/87850) David Malcolm
2018-11-10  7:01 ` Eric Gallager
2018-11-11 18:01   ` Martin Sebor
2018-11-11 21:02     ` David Malcolm
2018-11-12 21:32       ` Martin Sebor
2018-11-13 21:34         ` Jason Merrill
2018-11-15 21:48           ` [PATCH] v2: " David Malcolm
2018-11-16 18:13             ` Jason Merrill
2018-11-19 21:23               ` [PATCH] v3: " David Malcolm
2018-11-20  2:46                 ` Joseph Myers
2018-11-20 22:05                   ` David Malcolm
2018-11-20 22:23                     ` Joseph Myers
2018-11-30 23:01                       ` [PATCH] v4: " David Malcolm
2018-12-01 18:38                         ` Jason Merrill
2018-12-03 22:14                           ` Joseph Myers
2018-12-05 16:03                             ` Jason Merrill
2018-12-05 16:18                               ` David Malcolm
2018-11-21  0:36                 ` [PATCH] v3: " Jeff Law
2018-11-21  0:39                 ` Martin Sebor
2018-11-30 15:27                   ` David Malcolm

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).