This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[C PATCH] Add 'aka's on type printing in diagnostics
- From: Marek Polacek <polacek at redhat dot com>
- To: GCC Patches <gcc-patches at gcc dot gnu dot org>, "Joseph S. Myers" <joseph at codesourcery dot com>
- Date: Sat, 25 Oct 2014 17:16:28 +0200
- Subject: [C PATCH] Add 'aka's on type printing in diagnostics
- Authentication-results: sourceware.org; auth=none
This patch teaches the compiler to also print the typedef-stripped
version of a type when appropriate. C++ FE does this for a few
years now. With this patch we're able to say
note: expected 'B * {aka struct A *}' but argument is of type 'struct B *'
Compare that with
note: expected 'struct B *' but argument is of type 'struct B *'
that we output until recently.
We must be careful not to print the typedef-stripped part if it's
identical to the non-stripped part. I worked it out by using
a temporary c_pretty_printer and an obstack (C++'s type_to_string
uses an obstack too).
Bootstrapped/regtested on x86_64-linux and ppc64-linux, ok for trunk?
2014-10-25 Marek Polacek <polacek@redhat.com>
* c-objc-common.c (c_tree_printer) <case 'T'>: For a typedef name,
print the stripped version as well, if they're not the same.
* gcc.dg/diag-aka-1.c: New test.
* gcc.dg/pr13804-1.c: Adjust dg-error.
* gcc.dg/redecl-14.c: Likewise.
* gcc.dg/pr56980.c: Adjust dg-message.
diff --git gcc/c/c-objc-common.c gcc/c/c-objc-common.c
index 73bb297..f923458 100644
--- gcc/c/c-objc-common.c
+++ gcc/c/c-objc-common.c
@@ -135,23 +135,48 @@ c_tree_printer (pretty_printer *pp, text_info *text, const char *spec,
break;
case 'T':
- gcc_assert (TYPE_P (t));
- name = TYPE_NAME (t);
-
- if (name && TREE_CODE (name) == TYPE_DECL)
- {
- if (DECL_NAME (name))
- pp_identifier (cpp, lang_hooks.decl_printable_name (name, 2));
- else
- cpp->type_id (t);
- return true;
- }
- else
- {
+ {
+ gcc_assert (TYPE_P (t));
+ struct obstack *ob = pp_buffer (cpp)->obstack;
+ char *p = (char *) obstack_base (ob);
+ /* Remember the end of the initial dump. */
+ int len = obstack_object_size (ob);
+
+ name = TYPE_NAME (t);
+ if (name && TREE_CODE (name) == TYPE_DECL && DECL_NAME (name))
+ pp_identifier (cpp, lang_hooks.decl_printable_name (name, 2));
+ else
cpp->type_id (t);
- return true;
- }
- break;
+
+ /* If we're printing a type that involves typedefs, also print the
+ stripped version. But sometimes the stripped version looks
+ exactly the same, so we don't want it after all. To avoid
+ printing it in that case, we play ugly obstack games. */
+ if (TYPE_CANONICAL (t) && t != TYPE_CANONICAL (t))
+ {
+ c_pretty_printer cpp2;
+ /* Print the stripped version into a temporary printer. */
+ cpp2.type_id (TYPE_CANONICAL (t));
+ struct obstack *ob2 = cpp2.buffer->obstack;
+ /* Get the stripped version from the temporary printer. */
+ const char *aka = (char *) obstack_base (ob2);
+ int aka_len = obstack_object_size (ob2);
+ int type1_len = obstack_object_size (ob) - len;
+
+ /* If they are identical, bail out. */
+ if (aka_len == type1_len && memcmp (p + len, aka, aka_len) == 0)
+ return true;
+
+ /* They're not, print the stripped version now. */
+ pp_c_whitespace (cpp);
+ pp_left_brace (cpp);
+ pp_c_ws_string (cpp, "aka");
+ pp_c_whitespace (cpp);
+ cpp->type_id (TYPE_CANONICAL (t));
+ pp_right_brace (cpp);
+ }
+ return true;
+ }
case 'E':
if (TREE_CODE (t) == IDENTIFIER_NODE)
diff --git gcc/testsuite/gcc.dg/diag-aka-1.c gcc/testsuite/gcc.dg/diag-aka-1.c
index e69de29..87bc757 100644
--- gcc/testsuite/gcc.dg/diag-aka-1.c
+++ gcc/testsuite/gcc.dg/diag-aka-1.c
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+/* { dg-options "-Wc++-compat" } */
+
+typedef struct A { int i; } B;
+typedef struct T { int i; } T;
+typedef const float TFA;
+typedef TFA TFB;
+typedef TFB TFC;
+typedef int IA[];
+typedef IA *IAP;
+extern IAP arr[];
+
+void fn1 (B *); /* { dg-message "expected .B \\* {aka struct A \\*}. but argument is of type .struct B \\*." } */
+void fn2 (TFC *);
+
+void
+bar (B *b, int *i)
+{
+ fn1 ((struct B *) b); /* { dg-warning "passing argument" } */
+ fn2 (i); /* { dg-warning "passing argument" } */
+ sizeof (arr); /* { dg-error "invalid application of .sizeof. to incomplete type .int \\(\\*\\\[\\\]\\)\\\[\\\]." } */
+}
+
+int
+foo (void *a)
+{
+ T *t = a; /* { dg-warning "request for implicit conversion from .void \\*. to .T \\* {aka struct T \\*}. not" } */
+ return t->i;
+}
diff --git gcc/testsuite/gcc.dg/pr13804-1.c gcc/testsuite/gcc.dg/pr13804-1.c
index 4363678..65b238a 100644
--- gcc/testsuite/gcc.dg/pr13804-1.c
+++ gcc/testsuite/gcc.dg/pr13804-1.c
@@ -20,9 +20,9 @@ void
f (void)
{
x0.c; /* { dg-error "'struct s0' has no member named 'c'" } */
- x1.c; /* { dg-error "'S0' has no member named 'c'" } */
+ x1.c; /* { dg-error "'S0 {aka struct s0}' has no member named 'c'" } */
x2.c; /* { dg-error "'union u0' has no member named 'c'" } */
- x3.c; /* { dg-error "'U0' has no member named 'c'" } */
+ x3.c; /* { dg-error "'U0 {aka union u0}' has no member named 'c'" } */
x4->c; /* { dg-error "'struct s0' has no member named 'c'" } */
x5->c; /* { dg-error "'union u0' has no member named 'c'" } */
}
diff --git gcc/testsuite/gcc.dg/pr56980.c gcc/testsuite/gcc.dg/pr56980.c
index f48379a..27405ef 100644
--- gcc/testsuite/gcc.dg/pr56980.c
+++ gcc/testsuite/gcc.dg/pr56980.c
@@ -5,12 +5,12 @@ typedef struct A { int i; } B;
typedef union U { int i; } V;
typedef enum E { G } F;
-void foo_s (struct A); /* { dg-message "expected .struct A. but argument is of type .B \\*." } */
-void foo_u (union U); /* { dg-message "expected .union U. but argument is of type .V \\*." } */
-void foo_e (enum E); /* { dg-message "expected .enum E. but argument is of type .F \\*." } */
-void foo_sp (B *); /* { dg-message "expected .B \\*. but argument is of type .struct B \\*." } */
-void foo_up (V *); /* { dg-message "expected .V \\*. but argument is of type .union V \\*." } */
-void foo_ep (F *); /* { dg-message "expected .F \\*. but argument is of type .enum F \\*." } */
+void foo_s (struct A); /* { dg-message "expected .struct A. but argument is of type .B \\* {aka struct A \\*}." } */
+void foo_u (union U); /* { dg-message "expected .union U. but argument is of type .V \\* {aka union U \\*}." } */
+void foo_e (enum E); /* { dg-message "expected .enum E. but argument is of type .F \\* {aka enum E \\*}." } */
+void foo_sp (B *); /* { dg-message "expected .B \\* {aka struct A \\*}. but argument is of type .struct B \\*." } */
+void foo_up (V *); /* { dg-message "expected .V \\* {aka union U \\*}. but argument is of type .union V \\*." } */
+void foo_ep (F *); /* { dg-message "expected .F \\* {aka enum E \\*}. but argument is of type .enum F \\*." } */
void
bar (B *b, V *v, F *f)
diff --git gcc/testsuite/gcc.dg/redecl-14.c gcc/testsuite/gcc.dg/redecl-14.c
index b27c024..97003c1 100644
--- gcc/testsuite/gcc.dg/redecl-14.c
+++ gcc/testsuite/gcc.dg/redecl-14.c
@@ -18,5 +18,5 @@ f (void)
}
extern IAP a[];
extern IAP a[5];
- sizeof (*a[0]); /* { dg-error "invalid application of 'sizeof' to incomplete type 'IA'" } */
+ sizeof (*a[0]); /* { dg-error "invalid application of 'sizeof' to incomplete type 'IA {aka int\\\[\\\]}'" } */
}
Marek