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 <pola...@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