On Tue, 2015-11-10 at 17:55 +, Joseph Myers wrote:
> On Tue, 10 Nov 2015, David Malcolm wrote:
>
> > This is the most trivial example of a real fix-it example I could think
> > of: if the user writes
> > ptr.field
> > rather than ptr->field.
> >
> > gcc/c/ChangeLog:
> > * c-typeck.c (build_component_ref): Special-case POINTER_TYPE when
> > generating a "not a structure of union" error message, and
> > suggest a "->" rather than a ".", providing a fix-it hint.
>
> I wonder if this should be restricted to the case where the pointer's
> target is of structure or union type.
Probably. Attached is an updated version of the patch that does so.
> At least, if it's some other type,
> more of a fix is needed than just using -> (e.g. converting from void * to
> a pointer to the relevant type).
If so, then the attached patch simply does the status quo (I don't think
we want to try too hard for this case). I've added a test case for
this.
>From 12aa183d693db59cbc5d8a268749d577e729425c Mon Sep 17 00:00:00 2001
From: David Malcolm
Date: Tue, 8 Sep 2015 12:56:00 -0400
Subject: [PATCH] C FE: add fix-it hint for . vs ->
This is the most trivial example of a real fix-it example I could think
of: if the user writes
ptr.field
rather than ptr->field.
gcc/c/ChangeLog:
* c-typeck.c (should_suggest_deref_p): New function.
(build_component_ref): Special-case POINTER_TYPE when
generating a "not a structure of union" error message, and
suggest a "->" rather than a ".", providing a fix-it hint.
gcc/testsuite/ChangeLog:
* gcc.dg/fixits.c: New file.
---
gcc/c/c-typeck.c | 39 +++
gcc/testsuite/gcc.dg/fixits.c | 41 +
2 files changed, 80 insertions(+)
create mode 100644 gcc/testsuite/gcc.dg/fixits.c
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index c2e16c6..bdb2d12 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -2249,6 +2249,33 @@ lookup_field (tree type, tree component)
return tree_cons (NULL_TREE, field, NULL_TREE);
}
+/* Support function for build_component_ref's error-handling.
+
+ Given DATUM_TYPE, and "DATUM.COMPONENT", where DATUM is *not* a
+ struct or union, should we suggest "DATUM->COMPONENT" as a hint? */
+
+static bool
+should_suggest_deref_p (tree datum_type)
+{
+ /* We don't do it for Objective-C, since Objective-C 2.0 dot-syntax
+ allows "." for ptrs; we could be handling a failed attempt
+ to access a property. */
+ if (c_dialect_objc ())
+return false;
+
+ /* Only suggest it for pointers... */
+ if (TREE_CODE (datum_type) != POINTER_TYPE)
+return false;
+
+ /* ...to structs/unions. */
+ tree underlying_type = TREE_TYPE (datum_type);
+ enum tree_code code = TREE_CODE (underlying_type);
+ if (code == RECORD_TYPE || code == UNION_TYPE)
+return true;
+ else
+return false;
+}
+
/* Make an expression to refer to the COMPONENT field of structure or
union value DATUM. COMPONENT is an IDENTIFIER_NODE. LOC is the
location of the COMPONENT_REF. */
@@ -2336,6 +2363,18 @@ build_component_ref (location_t loc, tree datum, tree component)
return ref;
}
+ else if (should_suggest_deref_p (type))
+{
+ /* Special-case the error message for "ptr.field" for the case
+ where the user has confused "." vs "->". */
+ rich_location richloc (line_table, loc);
+ /* "loc" should be the "." token. */
+ richloc.add_fixit_replace (source_range::from_location (loc), "->");
+ error_at_rich_loc (&richloc,
+ "%qE is a pointer; did you mean to use %<->%>?",
+ datum);
+ return error_mark_node;
+}
else if (code != ERROR_MARK)
error_at (loc,
"request for member %qE in something not a structure or union",
diff --git a/gcc/testsuite/gcc.dg/fixits.c b/gcc/testsuite/gcc.dg/fixits.c
new file mode 100644
index 000..06c9995
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/fixits.c
@@ -0,0 +1,41 @@
+/* { dg-do compile } */
+/* { dg-options "-fdiagnostics-show-caret" } */
+
+struct foo { int x; };
+union u { int x; };
+
+/* Verify that we issue a hint for "." used with a ptr to a struct. */
+
+int test_1 (struct foo *ptr)
+{
+ return ptr.x; /* { dg-error "'ptr' is a pointer; did you mean to use '->'?" } */
+/* { dg-begin-multiline-output "" }
+ return ptr.x;
+ ^
+ ->
+ { dg-end-multiline-output "" } */
+}
+
+/* Likewise for a ptr to a union. */
+
+int test_2 (union u *ptr)
+{
+ return ptr.x; /* { dg-error "'ptr' is a pointer; did you mean to use '->'?" } */
+/* { dg-begin-multiline-output "" }
+ return ptr.x;
+ ^
+ ->
+ { dg-end-multiline-output "" } */
+}
+
+/* Verify that we don't issue a hint for a ptr to something that isn't a
+ struct or union. */
+
+int test_3 (void **ptr)
+{
+ return ptr.x; /* { dg-error "request for member 'x' in something not a structure or union" } */
+/* { dg-begin-multiline-output "" }
+ return