From patchwork Sat Oct 23 13:16:56 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicola Pero X-Patchwork-Id: 69002 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id 3062DB6F07 for ; Sun, 24 Oct 2010 00:17:26 +1100 (EST) Received: (qmail 25279 invoked by alias); 23 Oct 2010 13:17:24 -0000 Received: (qmail 24728 invoked by uid 22791); 23 Oct 2010 13:17:20 -0000 X-SWARE-Spam-Status: No, hits=-1.3 required=5.0 tests=AWL, BAYES_00, TW_BJ, T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from fencepost.gnu.org (HELO fencepost.gnu.org) (140.186.70.10) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Sat, 23 Oct 2010 13:17:01 +0000 Received: from eggs.gnu.org ([140.186.70.92]:58550) by fencepost.gnu.org with esmtps (TLS-1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.69) (envelope-from ) id 1P9dxz-0005QP-0C for gcc-patches@gnu.org; Sat, 23 Oct 2010 09:16:59 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1P9dxx-00086i-5r for gcc-patches@gnu.org; Sat, 23 Oct 2010 09:16:59 -0400 Received: from smtp131.iad.emailsrvr.com ([207.97.245.131]:58322) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1P9dxw-00086b-Vf for gcc-patches@gnu.org; Sat, 23 Oct 2010 09:16:57 -0400 Received: from localhost (localhost.localdomain [127.0.0.1]) by smtp43.relay.iad1a.emailsrvr.com (SMTP Server) with ESMTP id 29B822D043D for ; Sat, 23 Oct 2010 09:16:56 -0400 (EDT) Received: from dynamic5.wm-web.iad.mlsrvr.com (dynamic5.wm-web.iad1a.rsapps.net [192.168.2.146]) by smtp43.relay.iad1a.emailsrvr.com (SMTP Server) with ESMTP id 1710E2D041C for ; Sat, 23 Oct 2010 09:16:56 -0400 (EDT) Received: from meta-innovation.com (localhost [127.0.0.1]) by dynamic5.wm-web.iad.mlsrvr.com (Postfix) with ESMTP id 065988D0505 for ; Sat, 23 Oct 2010 09:16:56 -0400 (EDT) Received: by www2.webmail.us (Authenticated sender: nicola.pero@meta-innovation.com, from: nicola.pero@meta-innovation.com) with HTTP; Sat, 23 Oct 2010 15:16:56 +0200 (CEST) Date: Sat, 23 Oct 2010 15:16:56 +0200 (CEST) Subject: ObjC/ObjC++ - demangling of method and function names From: "Nicola Pero" To: "gcc-patches@gnu.org" MIME-Version: 1.0 X-Type: plain Message-ID: <1287839816.023829417@192.168.2.228> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 3) X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org This patch does a few things: * it fixes demangling C++ function names when compiling Objective-C++ (eg, __PRETTY_FUNCTION__ inside a C++ member function) * it fixes demangling Objective-C/Objective-C++ method names when they have no arguments and contain a '_' (not as the last character though). It's impossible to always get demangling right, but I managed to at least get "-(id)test_method" to demangle right. ;-) * it fixes Objective-C++ error messages to say "In function '-[NSObject release]' ..." instead of "In function '_i_NSObject__release' ..." :-) * it adds comments about the problems and ideas about how we could do the whole Objective-C/Objective-C++ pretty printing of method names much better (could be for next release). Three testcases are included, none of which would pass before this patch. A fourth testcase for the "In function '-[NSObject release]' ..." is included but has a TODO for the actual check because that line is automatically filtered out by the test suite. It's a minor TODO and I can fix that in stage 3 or for next release maybe (didn't want to spend hours looking at the testsuite right now). (the testcase would actually pass, it's a testsuite issue) Ok to apply to trunk ? Thanks PS: This does not fix the "'release' is deprecated" (instead of "'-[NSObject release]' is deprecated") message. That may be yet another patch. In gcc/cp/: 2010-10-23 Nicola Pero * tree.c (cxx_printable_name_internal): In Objective-C++, call objc_maybe_printable_name. In gcc/objc/: 2010-10-23 Nicola Pero * objc-act.c (OBJC_GEN_METHOD_LABEL): Updated comments. (objc_demangle): Return NULL if demangling can not be done because the string to demangle is not an Objective-C mangled method name. Be smarter in demangling method names so that at least for methods with no arguments we are able to almost always demangle '_' correctly. Updated comments. (objc_maybe_printable_name): New. (objc_printable_name): Call objc_maybe_printable_name. If it returns NULL, call cxx_printable_name in Objective-C++. In gcc/testsuite/: 2010-10-23 Nicola Pero * objc.dg/demangle-1.m: New test. * obj-c++.dg/demangle-1.mm: New test. * obj-c++.dg/demangle-2.mm: New test. * obj-c++.dg/demangle-3.mm: New test. In gcc/c-family/: 2010-10-23 Nicola Pero * c-common.h (objc_maybe_printable_name): New. * stub-objc.c (objc_maybe_printable_name): New. Index: c-family/ChangeLog =================================================================== --- c-family/ChangeLog (revision 165881) +++ c-family/ChangeLog (working copy) @@ -1,3 +1,8 @@ +2010-10-23 Nicola Pero + + * c-common.h (objc_maybe_printable_name): New. + * stub-objc.c (objc_maybe_printable_name): New. + 2010-10-22 Artjoms Sinkarovs Andrew Pinski Index: c-family/c-common.h =================================================================== --- c-family/c-common.h (revision 165881) +++ c-family/c-common.h (working copy) @@ -1048,6 +1048,7 @@ extern tree objc_build_getter_call (tree, tree); extern tree objc_build_setter_call (tree, tree); extern void objc_add_synthesize_declaration (location_t, tree); extern void objc_add_dynamic_declaration (location_t, tree); +extern const char * objc_maybe_printable_name (tree, int); /* The following are provided by the C and C++ front-ends, and called by ObjC/ObjC++. */ Index: c-family/stub-objc.c =================================================================== --- c-family/stub-objc.c (revision 165881) +++ c-family/stub-objc.c (working copy) @@ -359,6 +359,13 @@ objc_add_dynamic_declaration (location_t ARG_UNUSE { } +const char * +objc_maybe_printable_name (tree ARG_UNUSED (decl), + int ARG_UNUSED (v)) +{ + return NULL; +} + tree objc_build_throw_stmt (location_t ARG_UNUSED (loc), tree ARG_UNUSED (expr)) { Index: objc/objc-act.c =================================================================== --- objc/objc-act.c (revision 165881) +++ objc/objc-act.c (working copy) @@ -75,9 +75,14 @@ bool in_late_binary_op = false; #endif /* OBJCPLUS */ /* This is the default way of generating a method name. */ -/* I am not sure it is really correct. - Perhaps there's a danger that it will make name conflicts - if method names contain underscores. -- rms. */ +/* This has the problem that "test_method:argument:" and + "test:method_argument:" will generate the same name + ("_i_Test__test_method_argument_" for an instance method of the + class "Test"), so you can't have them both in the same class! + Moreover, the demangling (going from + "_i_Test__test_method_argument" back to the original name) is + undefined because there are two correct ways of demangling the + name. */ #ifndef OBJC_GEN_METHOD_LABEL #define OBJC_GEN_METHOD_LABEL(BUF, IS_INST, CLASS_NAME, CAT_NAME, SEL_NAME, NUM) \ do { \ @@ -10615,8 +10620,65 @@ dump_interface (FILE *fp, tree chain) fprintf (fp, "@end\n"); } -/* Demangle function for Objective-C */ +#if 0 +/* Produce the pretty printing for an Objective-C method. This is + currently unused, but could be handy while reorganizing the pretty + printing to be more robust. */ static const char * +objc_pretty_print_method (bool is_class_method, + const char *class_name, + const char *category_name, + const char *selector) +{ + if (category_name) + { + char *result = XNEWVEC (char, strlen (class_name) + strlen (category_name) + + strlen (selector) + 7); + + if (is_class_method) + sprintf (result, "+[%s(%s) %s]", class_name, category_name, selector); + else + sprintf (result, "-[%s(%s) %s]", class_name, category_name, selector); + + return result; + } + else + { + char *result = XNEWVEC (char, strlen (class_name) + + strlen (selector) + 5); + + if (is_class_method) + sprintf (result, "+[%s %s]", class_name, selector); + else + sprintf (result, "-[%s %s]", class_name, selector); + + return result; + } +} +#endif + +/* Demangle function for Objective-C. Attempt to demangle the + function name associated with a method (eg, going from + "_i_NSObject__class" to "-[NSObject class]"); usually for the + purpose of pretty printing or error messages. Return the demangled + name, or NULL if the string is not an Objective-C mangled method + name. + + Because of how the mangling is done, any method that has a '_' in + its original name is at risk of being demangled incorrectly. In + some cases there are multiple valid ways to demangle a method name + and there is no way we can decide. + + TODO: objc_demangle() can't always get it right; the right way to + get this correct for all method names would be to store the + Objective-C method name somewhere in the function decl. Then, + there is no demangling to do; we'd just pull the method name out of + the decl. As an additional bonus, when printing error messages we + could check for such a method name, and if we find it, we know the + function is actually an Objective-C method and we could print error + messages saying "In method '+[NSObject class]" instead of "In + function '+[NSObject class]" as we do now. */ +static const char * objc_demangle (const char *mangled) { char *demangled, *cp; @@ -10638,7 +10700,7 @@ objc_demangle (const char *mangled) if (cp == NULL) { free(demangled); /* not mangled name */ - return mangled; + return NULL; } if (cp[1] == '_') /* easy case: no category name */ { @@ -10652,31 +10714,105 @@ objc_demangle (const char *mangled) if (cp == 0) { free(demangled); /* not mangled name */ - return mangled; + return NULL; } *cp++ = ')'; *cp++ = ' '; /* overwriting 1st char of method name... */ strcpy(cp, mangled + (cp - demangled)); /* get it back */ } + /* Now we have the method name. We need to generally replace + '_' with ':' but trying to preserve '_' if it could only have + been in the mangled string because it was already in the + original name. In cases where it's ambiguous, we assume that + any '_' originated from a ':'. */ + + /* Initial '_'s in method name can't have been generating by + converting ':'s. Skip them. */ while (*cp && *cp == '_') - cp++; /* skip any initial underbars in method name */ - for (; *cp; cp++) - if (*cp == '_') - *cp = ':'; /* replace remaining '_' with ':' */ + cp++; + + /* If the method name does not end with '_', then it has no + arguments and there was no replacement of '_'s with ':'s + during mangling. Check for that case, and skip any + replacement if so. This at least guarantees that methods + with no arguments are always demangled correctly (unless the + original name ends with '_'). */ + if (*(mangled + strlen (mangled) - 1) != '_') + { + /* Skip to the end. */ + for (; *cp; cp++) + ; + } + else + { + /* Replace remaining '_' with ':'. This may get it wrong if + there were '_'s in the original name. In most cases it + is impossible to disambiguate. */ + for (; *cp; cp++) + if (*cp == '_') + *cp = ':'; + } *cp++ = ']'; /* closing right brace */ *cp++ = 0; /* string terminator */ return demangled; } else - return mangled; /* not an objc mangled name */ + return NULL; /* not an objc mangled name */ } +/* Try to pretty-print a decl. If the 'decl' is an Objective-C specific decl, + it return the printable name for it. If not, return NULL. */ const char * -objc_printable_name (tree decl, int kind ATTRIBUTE_UNUSED) +objc_maybe_printable_name (tree decl, int v ATTRIBUTE_UNUSED) { - return objc_demangle (IDENTIFIER_POINTER (DECL_NAME (decl))); + const char *decl_name = IDENTIFIER_POINTER (DECL_NAME (decl)); + + switch (TREE_CODE (decl)) + { + case FUNCTION_DECL: + return objc_demangle (decl_name); + break; + /* This unusual case (INSTANCE_METHOD_DECL and + CLASS_METHOD_DECL) seems to happen only in ObjC++ and to be a + by-product of the method attribute changes. It would be nice + to be able to print "-[NSObject autorelease] is deprecated", + but to do that, we'd need to store the class and method name + in the method decl, which we currently don't do. For now, + just return the name of the method. We don't return NULL, + because that may trigger further attempts to pretty-print the + decl in C/C++, but they wouldn't know how to pretty-print + it. */ + case INSTANCE_METHOD_DECL: + case CLASS_METHOD_DECL: + return decl_name; + break; + default: + return NULL; + break; + } } +/* Return a printable name for 'decl'. This first tries + objc_maybe_printable_name(), and if that fails, it hands it back to + C/C++. 'v' is the verbosity level, as this is a + LANG_HOOKS_DECL_PRINTABLE_NAME. */ +const char * +objc_printable_name (tree decl, int v) +{ + const char *demangled_name = objc_maybe_printable_name (decl, v); + + if (demangled_name != NULL) + return demangled_name; + else + { +#ifdef OBJCPLUS + return cxx_printable_name (decl, v); +#else + return IDENTIFIER_POINTER (DECL_NAME (decl)); +#endif + } +} + static void init_objc (void) { Index: objc/ChangeLog =================================================================== --- objc/ChangeLog (revision 165881) +++ objc/ChangeLog (working copy) @@ -1,3 +1,15 @@ +2010-10-23 Nicola Pero + + * objc-act.c (OBJC_GEN_METHOD_LABEL): Updated comments. + (objc_demangle): Return NULL if demangling can not be done because + the string to demangle is not an Objective-C mangled method name. + Be smarter in demangling method names so that at least for methods + with no arguments we are able to almost always demangle '_' correctly. + Updated comments. + (objc_maybe_printable_name): New. + (objc_printable_name): Call objc_maybe_printable_name. If it + returns NULL, call cxx_printable_name in Objective-C++. + 2010-10-21 Iain Sandoe Based on the CFString implementation in FSF apple/trunk branch. Index: testsuite/ChangeLog =================================================================== --- testsuite/ChangeLog (revision 165881) +++ testsuite/ChangeLog (working copy) @@ -1,3 +1,10 @@ +2010-10-23 Nicola Pero + + * objc.dg/demangle-1.m: New test. + * obj-c++.dg/demangle-1.mm: New test. + * obj-c++.dg/demangle-2.mm: New test. + * obj-c++.dg/demangle-3.mm: New test. + 2010-10-23 Jie Zhang PR rtl-optimization/37360 Index: testsuite/objc.dg/demangle-1.m =================================================================== --- testsuite/objc.dg/demangle-1.m (revision 0) +++ testsuite/objc.dg/demangle-1.m (revision 0) @@ -0,0 +1,56 @@ +/* Test demangling an Objective-C method. */ +/* { dg-do run } */ + +#include +#include +#include + +#include + +@interface DemangleTest +{ + Class isa; +} ++ (int) testFunction1; ++ (int) test_function2; ++ (int) __testFunction3: (int)unused andArgument: (char)unused2; +@end + +@implementation DemangleTest ++ (int) testFunction1 +{ + printf ("%s\n", __PRETTY_FUNCTION__); + return strcmp (__PRETTY_FUNCTION__, "+[DemangleTest testFunction1]"); +} +/* Note that in general, due to how mangling is done, it's impossible + to get the demangling right for all functions containing '_' in the + name. But at least we should be able to get that right for single + argument ones that don't end with '_', such as the following + one. */ ++ (int) test_function2 +{ + printf ("%s\n", __PRETTY_FUNCTION__); + return strcmp (__PRETTY_FUNCTION__, "+[DemangleTest test_function2]"); +} ++ (int) __testFunction3: (int)unused andArgument: (char)unused2 +{ + printf ("%s\n", __PRETTY_FUNCTION__); + return strcmp (__PRETTY_FUNCTION__, "+[DemangleTest __testFunction3:andArgument:]"); +} +@end + +int main () +{ + if ([DemangleTest testFunction1] != 0) + abort (); + + if ([DemangleTest test_function2] != 0) + abort (); + + if ([DemangleTest __testFunction3:0 andArgument: 'c'] != 0) + abort (); + + return 0; +} + + Index: testsuite/obj-c++.dg/demangle-1.mm =================================================================== --- testsuite/obj-c++.dg/demangle-1.mm (revision 0) +++ testsuite/obj-c++.dg/demangle-1.mm (revision 0) @@ -0,0 +1,35 @@ +/* Test demangling a C++ function. */ +/* { dg-do run } */ + +#include +#include +#include + +class demangle_test +{ +public: + /* Return 0 if the demangling test succeeds. */ + static int test_function1 () + { + std::cout << __PRETTY_FUNCTION__ << "\n"; + return std::strcmp (__PRETTY_FUNCTION__, "static int demangle_test::test_function1()"); + } + + /* Return 0 if the demangling test succeeds. */ + static int test_function2 (int ignored) + { + std::cout << __PRETTY_FUNCTION__ << "\n"; + return std::strcmp (__PRETTY_FUNCTION__, "static int demangle_test::test_function2(int)"); + } +}; + +int main () +{ + if (demangle_test::test_function1 () != 0) + abort (); + + if (demangle_test::test_function2 (0) != 0) + abort (); + + return 0; +} Index: testsuite/obj-c++.dg/demangle-2.mm =================================================================== --- testsuite/obj-c++.dg/demangle-2.mm (revision 0) +++ testsuite/obj-c++.dg/demangle-2.mm (revision 0) @@ -0,0 +1,50 @@ +/* Test demangling an Objective-C method. */ +/* { dg-do run } */ + +#include +#include +#include +#include + +@interface DemangleTest +{ + Class isa; +} ++ (int) testFunction1; ++ (int) test_function2; ++ (int) __testFunction3: (int)unused andArgument: (char)unused2; +@end + +@implementation DemangleTest ++ (int) testFunction1 +{ + std::cout << __PRETTY_FUNCTION__ << "\n"; + return std::strcmp (__PRETTY_FUNCTION__, "+[DemangleTest testFunction1]"); +} ++ (int) test_function2 +{ + std::cout << __PRETTY_FUNCTION__ << "\n"; + return std::strcmp (__PRETTY_FUNCTION__, "+[DemangleTest test_function2]"); +} ++ (int) __testFunction3: (int)unused andArgument: (char)unused2 +{ + std::cout << __PRETTY_FUNCTION__ << "\n"; + return std::strcmp (__PRETTY_FUNCTION__, "+[DemangleTest __testFunction3:andArgument:]"); +} +@end + +int main () +{ + if ([DemangleTest testFunction1] != 0) + abort (); + + if ([DemangleTest test_function2] != 0) + abort (); + + if ([DemangleTest __testFunction3:0 andArgument: 'c'] != 0) + abort (); + + return 0; +} + + Index: testsuite/obj-c++.dg/demangle-3.mm =================================================================== --- testsuite/obj-c++.dg/demangle-3.mm (revision 0) +++ testsuite/obj-c++.dg/demangle-3.mm (revision 0) @@ -0,0 +1,21 @@ +/* Test demangling an Objective-C method in error messages. */ +/* { dg-do compile } */ + +#include + +@interface DemangleTest +{ + Class isa; +} ++ (int) testFunction1; +@end + +@implementation DemangleTest ++ (int) testFunction1 +{ + /* TODO: Hack the testsuite so we can test that we get + dg-error "In function .+[DemangleTest testFunction1]." + At the moment, the message is filtered out. */ + z; /* { dg-error "was not declared" } */ +} +@end Index: cp/tree.c =================================================================== --- cp/tree.c (revision 165881) +++ cp/tree.c (working copy) @@ -1409,6 +1409,15 @@ cxx_printable_name_internal (tree decl, int v, boo static int ring_counter; int i; + /* If doing Objective-C++, give Objective-C a chance to demangle + Objective-C method names. */ + if (c_dialect_objc ()) + { + const char *demangled = objc_maybe_printable_name (decl, v); + if (demangled) + return demangled; + } + /* Only cache functions. */ if (v < 2 || TREE_CODE (decl) != FUNCTION_DECL Index: cp/ChangeLog =================================================================== --- cp/ChangeLog (revision 165881) +++ cp/ChangeLog (working copy) @@ -1,3 +1,8 @@ +2010-10-23 Nicola Pero + + * tree.c (cxx_printable_name_internal): In Objective-C++, call + objc_maybe_printable_name. + 2010-10-22 Jason Merrill PR c++/46129