From patchwork Sat Sep 24 00:41:46 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexandre Oliva X-Patchwork-Id: 674273 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]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3sgs0Q4rxGz9t25 for ; Sat, 24 Sep 2016 10:43:17 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b=QVCb1wnR; dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:mime-version:content-type; q=dns; s=default; b=VkueuWbkAN2mMiLbillOK+vCsfX4K0GoBNRJDMZXE9jwgQmAAY m5qBxM/mkCMbSp8wqXzz3BXsjsiwxa2/CCP4H0szvroE8B3kbfaNlX8MUl7/6fI6 8FziEpMsprTpERVw4AwXmFonmr+v1fK8bxUw84S5B8ymO4clwUrZU4wa8= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:mime-version:content-type; s= default; bh=ah+upNrZG3swntJerx3bIdMDBLM=; b=QVCb1wnRq2cDj1T5AAtV Pqftmfw8ILOvsiGkd/ZZ2R+hqXmN27TGmBxccLpGpG7z0iAaPE0qy5y53HFVRn3U zD6kxzzZnK7HH6mD9+AOLcTVvDHAO+1l5o7ll+z/IK72n3iqBPOAV9WifnGM9kQN yrE5/hZXrmrAuzEiTnLAs4Y= Received: (qmail 115998 invoked by alias); 24 Sep 2016 00:43:05 -0000 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 Received: (qmail 115932 invoked by uid 89); 24 Sep 2016 00:43:00 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=0.2 required=5.0 tests=BAYES_50, KAM_LAZY_DOMAIN_SECURITY, KAM_STOCKGEN, RP_MATCHES_RCVD, SPF_HELO_PASS, T_FILL_THIS_FORM_SHORT autolearn=ham version=3.3.2 spammy=forwards, anticipated, package_name, supplement X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Sat, 24 Sep 2016 00:42:28 +0000 Received: from int-mx14.intmail.prod.int.phx2.redhat.com (int-mx14.intmail.prod.int.phx2.redhat.com [10.5.11.27]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id BEE86C049D5B for ; Sat, 24 Sep 2016 00:42:26 +0000 (UTC) Received: from freie.home (ovpn03.gateway.prod.ext.phx2.redhat.com [10.5.9.3]) by int-mx14.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id u8O0gHnH023600 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO); Fri, 23 Sep 2016 20:42:19 -0400 Received: from livre.home (livre.home [172.31.160.2]) by freie.home (8.15.2/8.15.2) with ESMTP id u8O0fkqO004425; Fri, 23 Sep 2016 21:41:46 -0300 From: Alexandre Oliva To: gcc-patches@gcc.gnu.org Cc: jason@redhat.com Subject: [libcc1] add support for C++ Date: Fri, 23 Sep 2016 21:41:46 -0300 Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.5 (gnu/linux) MIME-Version: 1.0 This patchset adds support for the C++ language to libcc1. It updates a few patches for libcc1 by Jan Kratochvil, posted long ago but IIRC not reviewed; it updates a patch that adds support for representing aliases and trampolines in dwarf2+ debug info (useful for naming all cdtors clones), adding support for combined dwarf2 and vms debug output compared with the earlier version; and finally the actual extension of libcc1 to support the C++ language, with a few changes to the C++ front-end to make some functionality available to libcc1, to introduce symbol lookups through libcc1, to enable code snippets to be regarded as friends of every class, and other minor adjustments. Regstrapped on x86_64-linux-gnu and i686-linux-gnu; libcc1 was tested with GDB branch users/pmuldoon/c++compile, where GDB support for C++ compile code is being developed. Ok to install? https://gcc.gnu.org/ml/gcc-patches/2015-05/msg02218.html include/ChangeLog 2015-05-24 Jan Kratochvil * gcc-interface.h (enum gcc_base_api_version): Add GCC_FE_VERSION_1. libcc1/ChangeLog 2015-05-24 Jan Kratochvil * libcc1.cc (vtable): Update to GCC_FE_VERSION_1. (gcc_c_fe_context): Accept also GCC_FE_VERSION_1. --- include/gcc-interface.h | 3 ++- libcc1/libcc1.cc | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/include/gcc-interface.h b/include/gcc-interface.h index df7db6e..1b33e7d 100644 --- a/include/gcc-interface.h +++ b/include/gcc-interface.h @@ -44,7 +44,8 @@ struct gcc_base_context; enum gcc_base_api_version { - GCC_FE_VERSION_0 = 0 + GCC_FE_VERSION_0 = 0, + GCC_FE_VERSION_1 = 1, }; /* The operations defined by the GCC base API. This is the vtable for diff --git a/libcc1/libcc1.cc b/libcc1/libcc1.cc index 5295396..eec97f0 100644 --- a/libcc1/libcc1.cc +++ b/libcc1/libcc1.cc @@ -504,7 +504,7 @@ libcc1_destroy (struct gcc_base_context *s) static const struct gcc_base_vtable vtable = { - GCC_FE_VERSION_0, + GCC_FE_VERSION_1, libcc1_set_arguments, libcc1_set_source_file, libcc1_set_print_callback, @@ -523,7 +523,8 @@ struct gcc_c_context * gcc_c_fe_context (enum gcc_base_api_version base_version, enum gcc_c_api_version c_version) { - if (base_version != GCC_FE_VERSION_0 || c_version != GCC_C_FE_VERSION_0) + if ((base_version != GCC_FE_VERSION_0 && base_version != GCC_FE_VERSION_1) + || c_version != GCC_C_FE_VERSION_0) return NULL; return new libcc1 (&vtable, &c_vtable); https://gcc.gnu.org/ml/gcc-patches/2015-05/msg02219.html include/ChangeLog 2015-05-24 Jan Kratochvil * gcc-interface.h (enum gcc_base_api_version): Add comment to GCC_FE_VERSION_1. (struct gcc_base_vtable): Rename compile to compile_v0. Update comment for compile. New methods set_verbose and compile. libcc1/ChangeLog 2015-05-24 Jan Kratochvil * libcc1.cc: Include intl.h. (struct libcc1): Add field verbose. (libcc1::libcc1): Initialize it. (libcc1_set_verbose): New function. (libcc1_set_arguments): Print messages for VERBOSE. (libcc1_compile): Remove parameter verbose. Use VERBOSE from SELF. (libcc1_compile_v0): New function. (vtable): Use libcc1_compile_v0 and add libcc1_compile and libcc1_set_verbose. --- include/gcc-interface.h | 33 ++++++++++++++++++++++++++------- libcc1/libcc1.cc | 38 +++++++++++++++++++++++++++++++++----- 2 files changed, 59 insertions(+), 12 deletions(-) diff --git a/include/gcc-interface.h b/include/gcc-interface.h index 1b33e7d..70a5692 100644 --- a/include/gcc-interface.h +++ b/include/gcc-interface.h @@ -45,6 +45,8 @@ struct gcc_base_context; enum gcc_base_api_version { GCC_FE_VERSION_0 = 0, + + /* Deprecated method compile_v0. Added method set_verbose and compile. */ GCC_FE_VERSION_1 = 1, }; @@ -94,18 +96,35 @@ struct gcc_base_vtable const char *message), void *datum); - /* Perform the compilation. FILENAME is the name of the resulting - object file. VERBOSE can be set to cause GCC to print some - information as it works. Returns true on success, false on - error. */ + /* Deprecated GCC_FE_VERSION_0 variant of the GCC_FE_VERSION_1 + compile method. GCC_FE_VERSION_0 version verbose parameter has + been replaced by the set_verbose method. */ - int /* bool */ (*compile) (struct gcc_base_context *self, - const char *filename, - int /* bool */ verbose); + int /* bool */ (*compile_v0) (struct gcc_base_context *self, + const char *filename, + int /* bool */ verbose); /* Destroy this object. */ void (*destroy) (struct gcc_base_context *self); + + /* VERBOSE can be set to non-zero to cause GCC to print some + information as it works. Calling this method overrides its + possible previous calls. + + This method is only available since GCC_FE_VERSION_1. */ + + void (*set_verbose) (struct gcc_base_context *self, + int /* bool */ verbose); + + /* Perform the compilation. FILENAME is the name of the resulting + object file. Either set_triplet_regexp or set_driver_filename must + be called before. Returns true on success, false on error. + + This method is only available since GCC_FE_VERSION_1. */ + + int /* bool */ (*compile) (struct gcc_base_context *self, + const char *filename); }; /* The GCC object. */ diff --git a/libcc1/libcc1.cc b/libcc1/libcc1.cc index eec97f0..a527580 100644 --- a/libcc1/libcc1.cc +++ b/libcc1/libcc1.cc @@ -38,6 +38,7 @@ along with GCC; see the file COPYING3. If not see #include "xregex.h" #include "findcomp.hh" #include "compiler-name.h" +#include "intl.h" struct libcc1; @@ -66,6 +67,9 @@ struct libcc1 : public gcc_c_context std::vector args; std::string source_file; + + /* Non-zero as an equivalent to gcc driver option "-v". */ + bool verbose; }; // A local subclass of connection that holds a back-pointer to the @@ -97,7 +101,8 @@ libcc1::libcc1 (const gcc_base_vtable *v, print_function (NULL), print_datum (NULL), args (), - source_file () + source_file (), + verbose (false) { base.ops = v; c_ops = cv; @@ -306,6 +311,14 @@ make_regexp (const char *triplet_regexp, const char *compiler) return buf.str (); } +static void +libcc1_set_verbose (struct gcc_base_context *s, int /* bool */ verbose) +{ + libcc1 *self = (libcc1 *) s; + + self->verbose = verbose != 0; +} + static char * libcc1_set_arguments (struct gcc_base_context *s, const char *triplet_regexp, @@ -316,6 +329,10 @@ libcc1_set_arguments (struct gcc_base_context *s, int code; std::string rx = make_regexp (triplet_regexp, COMPILER_NAME); + // Simulate fnotice by fprintf. + if (self->verbose) + fprintf (stderr, _("searching for compiler matching regex %s\n"), + rx.c_str()); code = regcomp (&triplet, rx.c_str (), REG_EXTENDED | REG_NOSUB); if (code != 0) { @@ -341,6 +358,8 @@ libcc1_set_arguments (struct gcc_base_context *s, (char *) NULL); } regfree (&triplet); + if (self->verbose) + fprintf (stderr, _("found compiler %s\n"), compiler.c_str()); self->args.push_back (compiler); @@ -434,8 +453,7 @@ fork_exec (libcc1 *self, char **argv, int spair_fds[2], int stderr_fds[2]) static int libcc1_compile (struct gcc_base_context *s, - const char *filename, - int verbose) + const char *filename) { libcc1 *self = (libcc1 *) s; @@ -466,7 +484,7 @@ libcc1_compile (struct gcc_base_context *s, self->args.push_back ("-c"); self->args.push_back ("-o"); self->args.push_back (filename); - if (verbose) + if (self->verbose) self->args.push_back ("-v"); self->connection = new libcc1_connection (fds[0], stderr_fds[0], self); @@ -494,6 +512,14 @@ libcc1_compile (struct gcc_base_context *s, return fork_exec (self, argv, fds, stderr_fds); } +static int +libcc1_compile_v0 (struct gcc_base_context *s, const char *filename, + int verbose) +{ + libcc1_set_verbose (s, verbose); + return libcc1_compile (s, filename); +} + static void libcc1_destroy (struct gcc_base_context *s) { @@ -508,8 +534,10 @@ static const struct gcc_base_vtable vtable = libcc1_set_arguments, libcc1_set_source_file, libcc1_set_print_callback, + libcc1_compile_v0, + libcc1_destroy, + libcc1_set_verbose, libcc1_compile, - libcc1_destroy }; extern "C" gcc_c_fe_context_function gcc_c_fe_context; https://gcc.gnu.org/ml/gcc-patches/2015-05/msg02220.html include/ChangeLog 2015-05-24 Jan Kratochvil * gcc-interface.h (enum gcc_base_api_version): Update comment for GCC_FE_VERSION_1. (struct gcc_base_vtable): Rename set_arguments to set_arguments_v0. Add set_arguments, set_triplet_regexp and set_driver_filename. libcc1/ChangeLog 2015-05-24 Jan Kratochvil * libcc1.cc (libcc1): Add class compiler with field compilerp, class compiler_triplet_regexp and class compiler_driver_filename. (libcc1::libcc1): Initialize compilerp. (libcc1::~libcc1): Delete compilerp. (libcc1::compiler::find, libcc1::compiler_triplet_regexp::find) (libcc1::compiler_driver_filename::find): New methods. (libcc1_set_arguments): Remove parameter triplet_regexp. (libcc1_set_triplet_regexp, libcc1_set_driver_filename) (libcc1_set_arguments_v0): New functions. (vtable): Use libcc1_set_arguments_v0, add libcc1_set_arguments, libcc1_set_triplet_regexp and libcc1_set_driver_filename. --- include/gcc-interface.h | 61 ++++++++++++++++----- libcc1/libcc1.cc | 139 ++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 172 insertions(+), 28 deletions(-) diff --git a/include/gcc-interface.h b/include/gcc-interface.h index 70a5692..180c656 100644 --- a/include/gcc-interface.h +++ b/include/gcc-interface.h @@ -46,7 +46,9 @@ enum gcc_base_api_version { GCC_FE_VERSION_0 = 0, - /* Deprecated method compile_v0. Added method set_verbose and compile. */ + /* Deprecated methods set_arguments_v0 and compile_v0. Added methods + set_arguments, set_triplet_regexp, set_driver_filename, set_verbose and + compile. */ GCC_FE_VERSION_1 = 1, }; @@ -67,20 +69,12 @@ struct gcc_base_vtable unsigned int version; - /* Set the compiler's command-line options for the next compilation. - TRIPLET_REGEXP is a regular expression that is used to match the - configury triplet prefix to the compiler. - The arguments are copied by GCC. ARGV need not be - NULL-terminated. The arguments must be set separately for each - compilation; that is, after a compile is requested, the - previously-set arguments cannot be reused. - - This returns NULL on success. On failure, returns a malloc()d - error message. The caller is responsible for freeing it. */ + /* Deprecated GCC_FE_VERSION_0 variant of the GCC_FE_VERSION_1 + methods set_triplet_regexp and set_arguments. */ - char *(*set_arguments) (struct gcc_base_context *self, - const char *triplet_regexp, - int argc, char **argv); + char *(*set_arguments_v0) (struct gcc_base_context *self, + const char *triplet_regexp, + int argc, char **argv); /* Set the file name of the program to compile. The string is copied by the method implementation, but the caller must @@ -125,6 +119,45 @@ struct gcc_base_vtable int /* bool */ (*compile) (struct gcc_base_context *self, const char *filename); + + /* Set the compiler's command-line options for the next compilation. + The arguments are copied by GCC. ARGV need not be + NULL-terminated. The arguments must be set separately for each + compilation; that is, after a compile is requested, the + previously-set arguments cannot be reused. + + This returns NULL on success. On failure, returns a malloc()d + error message. The caller is responsible for freeing it. + + This method is only available since GCC_FE_VERSION_1. */ + + char *(*set_arguments) (struct gcc_base_context *self, + int argc, char **argv); + + /* Set TRIPLET_REGEXP as a regular expression that is used to match + the configury triplet prefix to the compiler. Calling this method + overrides possible previous call of itself or set_driver_filename. + + This returns NULL on success. On failure, returns a malloc()d + error message. The caller is responsible for freeing it. + + This method is only available since GCC_FE_VERSION_1. */ + + char *(*set_triplet_regexp) (struct gcc_base_context *self, + const char *triplet_regexp); + + /* DRIVER_FILENAME should be filename of the gcc compiler driver + program. It will be searched in PATH components like + TRIPLET_REGEXP. Calling this method overrides possible previous + call of itself or set_triplet_regexp. + + This returns NULL on success. On failure, returns a malloc()d + error message. The caller is responsible for freeing it. + + This method is only available since GCC_FE_VERSION_1. */ + + char *(*set_driver_filename) (struct gcc_base_context *self, + const char *driver_filename); }; /* The GCC object. */ diff --git a/libcc1/libcc1.cc b/libcc1/libcc1.cc index a527580..62eacde 100644 --- a/libcc1/libcc1.cc +++ b/libcc1/libcc1.cc @@ -70,6 +70,53 @@ struct libcc1 : public gcc_c_context /* Non-zero as an equivalent to gcc driver option "-v". */ bool verbose; + + /* Compiler to set by set_triplet_regexp or set_driver_filename. */ + class compiler + { + protected: + libcc1 *self_; + public: + compiler (libcc1 *self) : self_ (self) + { + } + virtual char *find (std::string &compiler) const; + virtual ~compiler () + { + } + } *compilerp; + + /* Compiler to set by set_triplet_regexp. */ + class compiler_triplet_regexp : public compiler + { + private: + std::string triplet_regexp_; + public: + virtual char *find (std::string &compiler) const; + compiler_triplet_regexp (libcc1 *self, std::string triplet_regexp) + : compiler (self), triplet_regexp_ (triplet_regexp) + { + } + virtual ~compiler_triplet_regexp () + { + } + }; + + /* Compiler to set by set_driver_filename. */ + class compiler_driver_filename : public compiler + { + private: + std::string driver_filename_; + public: + virtual char *find (std::string &compiler) const; + compiler_driver_filename (libcc1 *self, std::string driver_filename) + : compiler (self), driver_filename_ (driver_filename) + { + } + virtual ~compiler_driver_filename () + { + } + }; }; // A local subclass of connection that holds a back-pointer to the @@ -102,7 +149,8 @@ libcc1::libcc1 (const gcc_base_vtable *v, print_datum (NULL), args (), source_file (), - verbose (false) + verbose (false), + compilerp (new libcc1::compiler (this)) { base.ops = v; c_ops = cv; @@ -111,6 +159,7 @@ libcc1::libcc1 (const gcc_base_vtable *v, libcc1::~libcc1 () { delete connection; + delete compilerp; } @@ -319,20 +368,21 @@ libcc1_set_verbose (struct gcc_base_context *s, int /* bool */ verbose) self->verbose = verbose != 0; } -static char * -libcc1_set_arguments (struct gcc_base_context *s, - const char *triplet_regexp, - int argc, char **argv) +char * +libcc1::compiler::find (std::string &compiler ATTRIBUTE_UNUSED) const { - libcc1 *self = (libcc1 *) s; - regex_t triplet; - int code; + return xstrdup (_("Compiler has not been specified")); +} - std::string rx = make_regexp (triplet_regexp, COMPILER_NAME); - // Simulate fnotice by fprintf. - if (self->verbose) +char * +libcc1::compiler_triplet_regexp::find (std::string &compiler) const +{ + std::string rx = make_regexp (triplet_regexp_.c_str (), COMPILER_NAME); + if (self_->verbose) fprintf (stderr, _("searching for compiler matching regex %s\n"), rx.c_str()); + regex_t triplet; + int code; code = regcomp (&triplet, rx.c_str (), REG_EXTENDED | REG_NOSUB); if (code != 0) { @@ -348,7 +398,6 @@ libcc1_set_arguments (struct gcc_base_context *s, (char *) NULL); } - std::string compiler; if (!find_compiler (triplet, &compiler)) { regfree (&triplet); @@ -358,8 +407,32 @@ libcc1_set_arguments (struct gcc_base_context *s, (char *) NULL); } regfree (&triplet); - if (self->verbose) + if (self_->verbose) fprintf (stderr, _("found compiler %s\n"), compiler.c_str()); + return NULL; +} + +char * +libcc1::compiler_driver_filename::find (std::string &compiler) const +{ + // Simulate fnotice by fprintf. + if (self_->verbose) + fprintf (stderr, _("using explicit compiler filename %s\n"), + driver_filename_.c_str()); + compiler = driver_filename_; + return NULL; +} + +static char * +libcc1_set_arguments (struct gcc_base_context *s, + int argc, char **argv) +{ + libcc1 *self = (libcc1 *) s; + + std::string compiler; + char *errmsg = self->compilerp->find (compiler); + if (errmsg != NULL) + return errmsg; self->args.push_back (compiler); @@ -369,6 +442,41 @@ libcc1_set_arguments (struct gcc_base_context *s, return NULL; } +static char * +libcc1_set_triplet_regexp (struct gcc_base_context *s, + const char *triplet_regexp) +{ + libcc1 *self = (libcc1 *) s; + + delete self->compilerp; + self->compilerp = new libcc1::compiler_triplet_regexp (self, triplet_regexp); + return NULL; +} + +static char * +libcc1_set_driver_filename (struct gcc_base_context *s, + const char *driver_filename) +{ + libcc1 *self = (libcc1 *) s; + + delete self->compilerp; + self->compilerp = new libcc1::compiler_driver_filename (self, + driver_filename); + return NULL; +} + +static char * +libcc1_set_arguments_v0 (struct gcc_base_context *s, + const char *triplet_regexp, + int argc, char **argv) +{ + char *errmsg = libcc1_set_triplet_regexp (s, triplet_regexp); + if (errmsg != NULL) + return errmsg; + + return libcc1_set_arguments (s, argc, argv); +} + static void libcc1_set_source_file (struct gcc_base_context *s, const char *file) @@ -531,13 +639,16 @@ libcc1_destroy (struct gcc_base_context *s) static const struct gcc_base_vtable vtable = { GCC_FE_VERSION_1, - libcc1_set_arguments, + libcc1_set_arguments_v0, libcc1_set_source_file, libcc1_set_print_callback, libcc1_compile_v0, libcc1_destroy, libcc1_set_verbose, libcc1_compile, + libcc1_set_arguments, + libcc1_set_triplet_regexp, + libcc1_set_driver_filename, }; extern "C" gcc_c_fe_context_function gcc_c_fe_context; https://gcc.gnu.org/ml/gcc-patches/2015-05/msg02221.html libcc1/ChangeLog 2015-05-24 Jan Kratochvil * findcomp.cc: Include system.h. (search_dir): Return absolute filename. --- libcc1/findcomp.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libcc1/findcomp.cc b/libcc1/findcomp.cc index f2e0532..30cf39e 100644 --- a/libcc1/findcomp.cc +++ b/libcc1/findcomp.cc @@ -25,6 +25,7 @@ along with GCC; see the file COPYING3. If not see #include "libiberty.h" #include "xregex.h" #include "findcomp.hh" +#include "system.h" class scanner { @@ -68,7 +69,7 @@ search_dir (const regex_t ®exp, const std::string &dir, std::string *result) { if (regexec (®exp, filename, 0, NULL, 0) == 0) { - *result = filename; + *result = dir + DIR_SEPARATOR + filename; return true; } } Ping? https://gcc.gnu.org/ml/gcc-patches/2016-02/msg01407.html support aliases and trampolines in dwarf2 for gcc/ChangeLog * debug.h (struct gcc_debug_hooks): Add aliased_decl and trampoline_decl. * dwarf2out.c (dwarf2out_aliased_decl): New. (dwarf2out_trampoline_decl): New. (dwarf2_debug_hooks): Add them. (dwarf2_name): Skip leading '*' returned by langhook. (dwarf2_lineno_debug_hooks): Add dummies. * debug.c (do_nothing_debug_hooks): Likewise. * dbxout.c (dbx_debug_hooks, xcoff_debug_hooks): Likewise. * sdbout.c (sdb_debug_hooks): Likewise. * vmsdbgout.c (vmsdbgout_aliased_decl): New. (vmsdbgout_trampoline_decl): New. (vmsdbg_debug_hooks): Add them. * cgraph.h (cgraph_node::is_lang_trampoline): Declare. * cgraphunit.c: Include demangle.h. (cgraph_node::expand_thunk): Call function_decl debug_hook after assembly expansion. Do not mark thunk as ignored in gimple expansion. (cxx_cdtor_trampoline_p): New. (cgraph_node::is_lang_trampoline): New. (cgraph_node::assemble_thunks_and_aliases): Call the new debug_hooks. (symbol_table::output_weakrefs): Likewise. * varpool.c (varpool_node::assemble_aliases): Likewise. for gcc/cp/ChangeLog * method.c (make_alias_for): Copy DECL_IGNORED_P. for gcc/testsuite/ChangeLog * g++.dg/debug/dwarf2/cdtor-1.C: Adjust linkage_name count. * g++.dg/debug/dwarf2/cdtor-2.C: New. * g++.dg/debug/dwarf2/cdtor-3.C: New. * g++.dg/debug/dwarf2/covariant-1.C: New. * gcc.dg/debug/dwarf2/attr-alias-1.c: New. * gcc.dg/debug/dwarf2/attr-alias-2.c: New. * gcc.dg/debug/dwarf2/attr-weakref-1.c: New. * gcc.dg/debug/dwarf2/attr-weakref-2.c: New. --- gcc/cgraph.h | 4 + gcc/cgraphunit.c | 134 +++++++++++++++++++- gcc/cp/method.c | 1 gcc/dbxout.c | 4 + gcc/debug.c | 2 gcc/debug.h | 8 + gcc/dwarf2out.c | 100 +++++++++++++++ gcc/sdbout.c | 2 gcc/testsuite/g++.dg/debug/dwarf2/cdtor-1.C | 2 gcc/testsuite/g++.dg/debug/dwarf2/cdtor-2.C | 13 ++ gcc/testsuite/g++.dg/debug/dwarf2/cdtor-3.C | 17 +++ gcc/testsuite/g++.dg/debug/dwarf2/covariant-1.C | 24 ++++ gcc/testsuite/gcc.dg/debug/dwarf2/attr-alias-1.c | 10 + gcc/testsuite/gcc.dg/debug/dwarf2/attr-alias-2.c | 10 + gcc/testsuite/gcc.dg/debug/dwarf2/attr-weakref-1.c | 10 + gcc/testsuite/gcc.dg/debug/dwarf2/attr-weakref-2.c | 10 + gcc/varpool.c | 8 + gcc/vmsdbgout.c | 22 +++ 18 files changed, 369 insertions(+), 12 deletions(-) create mode 100644 gcc/testsuite/g++.dg/debug/dwarf2/cdtor-2.C create mode 100644 gcc/testsuite/g++.dg/debug/dwarf2/cdtor-3.C create mode 100644 gcc/testsuite/g++.dg/debug/dwarf2/covariant-1.C create mode 100644 gcc/testsuite/gcc.dg/debug/dwarf2/attr-alias-1.c create mode 100644 gcc/testsuite/gcc.dg/debug/dwarf2/attr-alias-2.c create mode 100644 gcc/testsuite/gcc.dg/debug/dwarf2/attr-weakref-1.c create mode 100644 gcc/testsuite/gcc.dg/debug/dwarf2/attr-weakref-2.c diff --git a/gcc/cgraph.h b/gcc/cgraph.h index ecafe63..fcde9e1 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -1154,6 +1154,10 @@ public: external means. */ inline void mark_force_output (void); + /* Return true when function is a language-defined trampoline, e.g., + C++ ctor and dtor "thunks" that just call the unified cdtor. */ + bool is_lang_trampoline (void); + /* Return true when function can be marked local. */ bool local_p (void); diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c index 4141bad..4a63735 100644 --- a/gcc/cgraphunit.c +++ b/gcc/cgraphunit.c @@ -204,6 +204,7 @@ along with GCC; see the file COPYING3. If not see #include "dbgcnt.h" #include "tree-chkp.h" #include "lto-section-names.h" +#include "demangle.h" /* Queue of cgraph nodes scheduled to be added into cgraph. This is a secondary queue used during optimization to accommodate passes that @@ -1644,6 +1645,12 @@ cgraph_node::expand_thunk (bool output_asm_thunks, bool force_gimple_thunk) assemble_end_function (thunk_fndecl, fnname); insn_locations_finalize (); init_insn_lengths (); + + timevar_push (TV_SYMOUT); + if (!DECL_IGNORED_P (thunk_fndecl)) + (*debug_hooks->function_decl) (thunk_fndecl); + timevar_pop (TV_SYMOUT); + free_after_compilation (cfun); TREE_ASM_WRITTEN (thunk_fndecl) = 1; thunk.thunk_p = false; @@ -1685,7 +1692,6 @@ cgraph_node::expand_thunk (bool output_asm_thunks, bool force_gimple_thunk) resolve_unique_section (thunk_fndecl, 0, flag_function_sections); - DECL_IGNORED_P (thunk_fndecl) = 1; bitmap_obstack_initialize (NULL); if (thunk.virtual_offset_p) @@ -1900,6 +1906,92 @@ cgraph_node::expand_thunk (bool output_asm_thunks, bool force_gimple_thunk) return true; } +/* Return true if DECL is a cdtor trampoline for unified cdtor + TARGET. */ + +static bool +cxx_cdtor_trampoline_p (tree decl, tree target) +{ + if (DECL_ABSTRACT_ORIGIN (decl)) + return false; + + if (!DECL_CXX_CONSTRUCTOR_P (decl) && !DECL_CXX_DESTRUCTOR_P (decl)) + return false; + + if (DECL_CXX_CONSTRUCTOR_P (decl) != DECL_CXX_CONSTRUCTOR_P (target)) + return false; + + if (DECL_CXX_DESTRUCTOR_P (decl) != DECL_CXX_DESTRUCTOR_P (target)) + return false; + + gcc_assert (DECL_ASSEMBLER_NAME_SET_P (decl)); + gcc_assert (DECL_ASSEMBLER_NAME_SET_P (target)); + + const char *dname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); + const char *tname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (target)); + + unsigned int i = strlen (dname); + if (i != strlen (tname)) + return false; + + gcc_assert (i); + + /* C1 and C2 ctors may be trampolines to C4; D0, D1 and D2 dtors may + be trampolines to D4. Check their mangled names, so that the + test will work even during LTO compilations, when the cdtor + clones retrofitted into trampolines might not be right after the + unified one in the DECL_CHAIN, and we don't have C++-specific + data structures or lang hooks to check that the cdtors are of + different kinds and belong to the same class. + + Alas, just checking that the assembler name has e.g. C2 vs C4 as + the only difference could find false positives, e.g., if there + are cdtors with the same signature (aside from the THIS pointer) + in classes whose names contain C2 and C4, say _ZN2C2C1Ev AKA + C2::C2() and _ZN2C4C1Ev AKA C4::C4(). + + So, after checking that we found viable distinguishing characters + at the expected place, we check that the cdtors are of different + kinds using the demangler. Yuck. */ + bool found = false; + while (i--) + if (dname[i] != tname[i]) + { + if (!found + && tname[i] == '4' && i && tname[i-1] == dname[i-1] + && (((dname[i-1] == 'C' || dname[i-1] == 'D') + && (dname[i] == '1' || dname[i] == '2')) + || (dname[i-1] == 'D' && dname[i] == '0'))) + found = true; + else + return false; + } + + if (DECL_CXX_CONSTRUCTOR_P (decl)) + return is_gnu_v3_mangled_ctor (tname) == gnu_v3_unified_ctor + && is_gnu_v3_mangled_ctor (dname) != gnu_v3_unified_ctor; + else if (DECL_CXX_DESTRUCTOR_P (decl)) + return is_gnu_v3_mangled_dtor (tname) == gnu_v3_unified_dtor + && is_gnu_v3_mangled_dtor (dname) != gnu_v3_unified_dtor; + else + gcc_unreachable (); +} + +/* Return true when function is as a language-defined trampoline, + e.g., C++ ctor and dtor "thunks" that just call the unified + cdtor. */ + +bool +cgraph_node::is_lang_trampoline (void) +{ + if (!callees || callees->next_callee) + return false; + + tree target = callees->callee->decl; + + return (cxx_cdtor_trampoline_p (decl, target)); +} + /* Assemble thunks and aliases associated to node. */ void @@ -1918,9 +2010,17 @@ cgraph_node::assemble_thunks_and_aliases (void) e = e->next_caller; thunk->expand_thunk (true, false); thunk->assemble_thunks_and_aliases (); + if (!DECL_IGNORED_P (thunk->decl) && !DECL_IGNORED_P (decl)) + (*debug_hooks->trampoline_decl) (thunk->decl, decl); } else - e = e->next_caller; + { + if (e->caller->is_lang_trampoline () + && !DECL_IGNORED_P (e->caller->decl) && !DECL_IGNORED_P (decl)) + (*debug_hooks->trampoline_decl) (e->caller->decl, decl); + + e = e->next_caller; + } FOR_EACH_ALIAS (this, ref) { @@ -1934,6 +2034,8 @@ cgraph_node::assemble_thunks_and_aliases (void) TREE_ASM_WRITTEN (decl) = 1; do_assemble_alias (alias->decl, DECL_ASSEMBLER_NAME (decl)); + if (!DECL_IGNORED_P (alias->decl) && !DECL_IGNORED_P (decl)) + (*debug_hooks->aliased_decl) (alias->decl, decl); alias->assemble_thunks_and_aliases (); TREE_ASM_WRITTEN (decl) = saved_written; } @@ -2355,7 +2457,7 @@ symbol_table::output_weakrefs (void) || !TREE_ASM_WRITTEN (cnode->instrumented_version->decl)) && node->weakref) { - tree target; + tree target, target_decl; /* Weakrefs are special by not requiring target definition in current compilation unit. It is thus bit hard to work out what we want to @@ -2363,17 +2465,33 @@ symbol_table::output_weakrefs (void) When alias target is defined, we need to fetch it from symtab reference, otherwise it is pointed to by alias_target. */ if (node->alias_target) - target = (DECL_P (node->alias_target) - ? DECL_ASSEMBLER_NAME (node->alias_target) - : node->alias_target); + { + if (DECL_P (node->alias_target)) + { + target_decl = node->alias_target; + target = DECL_ASSEMBLER_NAME (target_decl); + } + else + { + target_decl = NULL_TREE; + target = node->alias_target; + } + } else if (node->analyzed) - target = DECL_ASSEMBLER_NAME (node->get_alias_target ()->decl); + { + target_decl = node->get_alias_target ()->decl; + target = DECL_ASSEMBLER_NAME (target_decl); + } else { gcc_unreachable (); - target = get_alias_symbol (node->decl); + target_decl = node->decl; + target = get_alias_symbol (target_decl); } do_assemble_alias (node->decl, target); + if (target_decl && !DECL_IGNORED_P (node->decl) + && !DECL_IGNORED_P (target_decl)) + (*debug_hooks->aliased_decl) (node->decl, target_decl); } } diff --git a/gcc/cp/method.c b/gcc/cp/method.c index 957ea39..01aa249 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -219,6 +219,7 @@ make_alias_for (tree target, tree newid) } DECL_EXTERNAL (alias) = 0; DECL_ARTIFICIAL (alias) = 1; + DECL_IGNORED_P (alias) = DECL_IGNORED_P (target); DECL_TEMPLATE_INSTANTIATED (alias) = 0; if (TREE_CODE (alias) == FUNCTION_DECL) { diff --git a/gcc/dbxout.c b/gcc/dbxout.c index 9aa1567..5ee2135 100644 --- a/gcc/dbxout.c +++ b/gcc/dbxout.c @@ -372,6 +372,8 @@ const struct gcc_debug_hooks dbx_debug_hooks = debug_nothing_tree_tree_tree_bool, /* imported_module_or_decl */ debug_nothing_tree, /* deferred_inline_function */ debug_nothing_tree, /* outlining_inline_function */ + debug_nothing_tree_tree, /* aliased_decl */ + debug_nothing_tree_tree, /* trampoline_decl */ debug_nothing_rtx_code_label, /* label */ dbxout_handle_pch, /* handle_pch */ debug_nothing_rtx_insn, /* var_location */ @@ -412,6 +414,8 @@ const struct gcc_debug_hooks xcoff_debug_hooks = debug_nothing_tree_tree_tree_bool, /* imported_module_or_decl */ debug_nothing_tree, /* deferred_inline_function */ debug_nothing_tree, /* outlining_inline_function */ + debug_nothing_tree_tree, /* aliased_decl */ + debug_nothing_tree_tree, /* trampoline_decl */ debug_nothing_rtx_code_label, /* label */ dbxout_handle_pch, /* handle_pch */ debug_nothing_rtx_insn, /* var_location */ diff --git a/gcc/debug.c b/gcc/debug.c index 3d658e8..3494e6c 100644 --- a/gcc/debug.c +++ b/gcc/debug.c @@ -50,6 +50,8 @@ const struct gcc_debug_hooks do_nothing_debug_hooks = debug_nothing_tree_tree_tree_bool, /* imported_module_or_decl */ debug_nothing_tree, /* deferred_inline_function */ debug_nothing_tree, /* outlining_inline_function */ + debug_nothing_tree_tree, /* aliased_decl */ + debug_nothing_tree_tree, /* trampoline_decl */ debug_nothing_rtx_code_label, /* label */ debug_nothing_int, /* handle_pch */ debug_nothing_rtx_insn, /* var_location */ diff --git a/gcc/debug.h b/gcc/debug.h index 34b63d7..bcb188d 100644 --- a/gcc/debug.h +++ b/gcc/debug.h @@ -155,6 +155,14 @@ struct gcc_debug_hooks the inline before it gets mangled by optimization. */ void (* outlining_inline_function) (tree decl); + /* ALIAS is a declaration whose symbol was defined as an alias to + DECL's symbol. Called right after outputting the alias + definition. */ + void (* aliased_decl) (tree alias, tree decl); + + /* TRAMPOLINE is a function defined as a trampoline to DECL. */ + void (* trampoline_decl) (tree trampoline, tree decl); + /* Called from final_scan_insn for any CODE_LABEL insn whose LABEL_NAME is non-null. */ void (* label) (rtx_code_label *); diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index 49e31c1..bfa3929 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -2503,6 +2503,8 @@ static void dwarf2out_begin_function (tree); static void dwarf2out_end_function (unsigned int); static void dwarf2out_register_main_translation_unit (tree unit); static void dwarf2out_set_name (tree, tree); +static void dwarf2out_aliased_decl (tree, tree); +static void dwarf2out_trampoline_decl (tree, tree); /* The debug hooks structure. */ @@ -2542,6 +2544,8 @@ const struct gcc_debug_hooks dwarf2_debug_hooks = emitting the abstract description of inline functions until something tries to reference them. */ dwarf2out_abstract_function, /* outlining_inline_function */ + dwarf2out_aliased_decl, /* aliased_decl */ + dwarf2out_trampoline_decl, /* trampoline_decl */ debug_nothing_rtx_code_label, /* label */ debug_nothing_int, /* handle_pch */ dwarf2out_var_location, @@ -2580,6 +2584,8 @@ const struct gcc_debug_hooks dwarf2_lineno_debug_hooks = debug_nothing_tree_tree_tree_bool, /* imported_module_or_decl */ debug_nothing_tree, /* deferred_inline_function */ debug_nothing_tree, /* outlining_inline_function */ + debug_nothing_tree_tree, /* aliased_decl */ + debug_nothing_tree_tree, /* trampoline_decl */ debug_nothing_rtx_code_label, /* label */ debug_nothing_int, /* handle_pch */ debug_nothing_rtx_insn, /* var_location */ @@ -9772,7 +9778,10 @@ dwarf2_name (tree decl, int scope) { if (DECL_NAMELESS (decl)) return NULL; - return lang_hooks.dwarf_name (decl, scope ? 1 : 0); + const char *name = lang_hooks.dwarf_name (decl, scope ? 1 : 0); + if (name && name[0] == '*') + name++; + return name; } /* Add a new entry to .debug_pubnames if appropriate. */ @@ -24242,6 +24251,95 @@ dwarf2out_imported_module_or_decl (tree decl, tree name, tree context, dwarf2out_imported_module_or_decl_1 (decl, name, context, scope_die); } +/* Output debug info indicating that ALIAS is an alias to DECL. */ + +static void +dwarf2out_aliased_decl (tree alias, tree decl) +{ + if (debug_info_level <= DINFO_LEVEL_TERSE) + return; + + if (!(dwarf_version >= 3 || !dwarf_strict)) + return; + + if (DECL_IGNORED_P (decl) || DECL_IGNORED_P (alias)) + return; + + dw_die_ref decl_die = lookup_decl_die (decl); + + if (!decl_die) + return; + + dw_die_ref old_alias_die = lookup_decl_die (alias); + + if (old_alias_die && TREE_CODE (alias) == FUNCTION_DECL) + /* FIXME: we have a specification and probably a definition that + turned into an alias. Location information of the aliased + definition is most certainly not suitable for this alias. */ + return; + + dw_die_ref alias_die = new_die (DW_TAG_imported_declaration, + comp_unit_die (), NULL_TREE); + + add_AT_die_ref (alias_die, DW_AT_import, decl_die); + + /* ??? It would be nice if we could just link back to the symbol + declaration, but DW_AT_specification is not a welcome attribute + for a DW_TAG_imported_declaration. */ + if (0 && old_alias_die) + { + add_AT_die_ref (alias_die, DW_AT_specification, old_alias_die); + return; + } + + equate_decl_number_to_die (alias, alias_die); + + if (TREE_PUBLIC (alias)) + add_AT_flag (alias_die, DW_AT_external, 1); + + { + bool save_artificial = DECL_ARTIFICIAL (alias); + /* Temporarily set DECL_ARTIFICIAL so that we don't emit src coords + attributes. */ + DECL_ARTIFICIAL (alias) = true; + add_name_and_src_coords_attributes (alias_die, alias); + DECL_ARTIFICIAL (alias) = save_artificial; + } + + add_pubname (alias, alias_die); + if (DECL_ARTIFICIAL (alias)) + add_AT_flag (alias_die, DW_AT_artificial, 1); + add_accessibility_attribute (alias_die, alias); +} + +/* Output debug info indicating that TRAMPOLINE is a trampoline to + DECL. */ + +static void +dwarf2out_trampoline_decl (tree trampoline, tree decl) +{ + if (debug_info_level <= DINFO_LEVEL_TERSE) + return; + + if (!(dwarf_version >= 3 || !dwarf_strict)) + return; + + if (DECL_IGNORED_P (decl) || DECL_IGNORED_P (trampoline)) + return; + + dw_die_ref decl_die = lookup_decl_die (decl); + + if (!decl_die) + return; + + dw_die_ref trampoline_die = lookup_decl_die (trampoline); + + if (!trampoline_die) + return; + + add_AT_die_ref (trampoline_die, DW_AT_trampoline, decl_die); +} + /* Output debug information for namelists. */ static dw_die_ref diff --git a/gcc/sdbout.c b/gcc/sdbout.c index 7eea772..3cb0e25 100644 --- a/gcc/sdbout.c +++ b/gcc/sdbout.c @@ -301,6 +301,8 @@ const struct gcc_debug_hooks sdb_debug_hooks = debug_nothing_tree_tree_tree_bool, /* imported_module_or_decl */ debug_nothing_tree, /* deferred_inline_function */ debug_nothing_tree, /* outlining_inline_function */ + debug_nothing_tree_tree, /* aliased_decl */ + debug_nothing_tree_tree, /* trampoline_decl */ sdbout_label, /* label */ debug_nothing_int, /* handle_pch */ debug_nothing_rtx_insn, /* var_location */ diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/cdtor-1.C b/gcc/testsuite/g++.dg/debug/dwarf2/cdtor-1.C index c0d3d22..71efae8 100644 --- a/gcc/testsuite/g++.dg/debug/dwarf2/cdtor-1.C +++ b/gcc/testsuite/g++.dg/debug/dwarf2/cdtor-1.C @@ -14,4 +14,4 @@ main() K k; } -// { dg-final {scan-assembler-times " DW_AT_\[MIPS_\]*linkage_name" 4 } } +// { dg-final {scan-assembler-times " DW_AT_\[MIPS_\]*linkage_name" 6 } } diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/cdtor-2.C b/gcc/testsuite/g++.dg/debug/dwarf2/cdtor-2.C new file mode 100644 index 0000000..0737e43 --- /dev/null +++ b/gcc/testsuite/g++.dg/debug/dwarf2/cdtor-2.C @@ -0,0 +1,13 @@ +// { dg-options "-gdwarf-2 -dA" } +/* { dg-require-alias "" } */ +// { dg-do compile } + +struct foo { + foo (); + ~foo (); +}; + +foo::foo () {} +foo::~foo () {} + +// { dg-final { scan-assembler-times " DW_AT_import" 2 } } diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/cdtor-3.C b/gcc/testsuite/g++.dg/debug/dwarf2/cdtor-3.C new file mode 100644 index 0000000..d500e82 --- /dev/null +++ b/gcc/testsuite/g++.dg/debug/dwarf2/cdtor-3.C @@ -0,0 +1,17 @@ +// { dg-options "-gdwarf-2 -fdeclone-ctor-dtor -dA" } +// { dg-do compile } + +struct bar { + bar (); + ~bar (); +}; + +struct foo : virtual bar { + foo (); + ~foo (); +}; + +foo::foo () {} +foo::~foo () {} + +// { dg-final { scan-assembler-times " DW_AT_trampoline" 4 } } diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/covariant-1.C b/gcc/testsuite/g++.dg/debug/dwarf2/covariant-1.C new file mode 100644 index 0000000..1f4326a --- /dev/null +++ b/gcc/testsuite/g++.dg/debug/dwarf2/covariant-1.C @@ -0,0 +1,24 @@ +// { dg-options "-gdwarf-2 -dA" } +/* { dg-require-alias "" } */ +// { dg-do compile } + +class A { +public: + virtual A* getThis(); +}; + +class B { + int a; +public: + virtual B* getThis(); +}; + +class AB : public A, public B { +public: + virtual AB* getThis(); +}; + +AB* AB::getThis() { return this; } + +// { dg-final { scan-assembler-times " DW_AT_import" 2 } } +// { dg-final { scan-assembler-times " DW_AT_trampoline" 1 } } diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/attr-alias-1.c b/gcc/testsuite/gcc.dg/debug/dwarf2/attr-alias-1.c new file mode 100644 index 0000000..9968856 --- /dev/null +++ b/gcc/testsuite/gcc.dg/debug/dwarf2/attr-alias-1.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-require-alias "" } */ +/* { dg-options "-gdwarf-2 -dA" } */ + +static int f1 (void) { return 0; } +extern int g1 (void) __attribute__((__alias__("f1"))); + +int f () { return g1 (); } + +// { dg-final { scan-assembler-times " DW_AT_import" 1 } } diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/attr-alias-2.c b/gcc/testsuite/gcc.dg/debug/dwarf2/attr-alias-2.c new file mode 100644 index 0000000..27201d4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/debug/dwarf2/attr-alias-2.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-require-alias "" } */ +/* { dg-options "-gdwarf-2 -dA" } */ + +static int i1 = 0; +extern int i2 __attribute__((__alias__("i1"))); + +int f () { return i2; } + +// { dg-final { scan-assembler-times " DW_AT_import" 1 } } diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/attr-weakref-1.c b/gcc/testsuite/gcc.dg/debug/dwarf2/attr-weakref-1.c new file mode 100644 index 0000000..b53bd05 --- /dev/null +++ b/gcc/testsuite/gcc.dg/debug/dwarf2/attr-weakref-1.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-require-weak "" } */ +/* { dg-options "-gdwarf-2 -dA" } */ + +int f1 (void) { return 0; } +static int g1 (void) __attribute__((__weakref__("f1"))); + +int f () { return g1 (); } + +// { dg-final { scan-assembler-times " DW_AT_import" 1 } } diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/attr-weakref-2.c b/gcc/testsuite/gcc.dg/debug/dwarf2/attr-weakref-2.c new file mode 100644 index 0000000..6020202 --- /dev/null +++ b/gcc/testsuite/gcc.dg/debug/dwarf2/attr-weakref-2.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-require-weak "" } */ +/* { dg-options "-gdwarf-2 -dA" } */ + +int i1 = 0; +static int i2 __attribute__((__weakref__("i1"))); + +int f () { return i2; } + +// { dg-final { scan-assembler-times " DW_AT_import" 1 } } diff --git a/gcc/varpool.c b/gcc/varpool.c index e5f991e..f3a5df2 100644 --- a/gcc/varpool.c +++ b/gcc/varpool.c @@ -545,8 +545,12 @@ varpool_node::assemble_aliases (void) { varpool_node *alias = dyn_cast (ref->referring); if (!alias->transparent_alias) - do_assemble_alias (alias->decl, - DECL_ASSEMBLER_NAME (decl)); + { + do_assemble_alias (alias->decl, + DECL_ASSEMBLER_NAME (decl)); + if (!DECL_IGNORED_P (alias->decl) && !DECL_IGNORED_P (decl)) + (*debug_hooks->aliased_decl) (alias->decl, decl); + } alias->assemble_aliases (); } } diff --git a/gcc/vmsdbgout.c b/gcc/vmsdbgout.c index 7c6d64d..40f6d41 100644 --- a/gcc/vmsdbgout.c +++ b/gcc/vmsdbgout.c @@ -168,6 +168,8 @@ static void vmsdbgout_early_global_decl (tree); static void vmsdbgout_late_global_decl (tree); static void vmsdbgout_type_decl (tree, int); static void vmsdbgout_abstract_function (tree); +static void vmsdbgout_aliased_decl (tree, tree); +static void vmsdbgout_trampoline_decl (tree, tree); /* The debug hooks structure. */ @@ -198,6 +200,8 @@ const struct gcc_debug_hooks vmsdbg_debug_hooks debug_nothing_tree_tree_tree_bool, /* imported_module_or_decl */ debug_nothing_tree, /* deferred_inline_function */ vmsdbgout_abstract_function, + vmsdbgout_aliased_decl, /* aliased_decl */ + vmsdbgout_trampoline_decl, /* trampoline_decl */ debug_nothing_rtx_code_label, /* label */ debug_nothing_int, /* handle_pch */ debug_nothing_rtx_insn, /* var_location */ @@ -1549,6 +1553,24 @@ vmsdbgout_abstract_function (tree decl) (*dwarf2_debug_hooks.outlining_inline_function) (decl); } +/* Not implemented in VMS Debug. */ + +static void +vmsdbgout_aliased_decl (tree alias, tree decl) +{ + if (write_symbols == VMS_AND_DWARF2_DEBUG) + (*dwarf2_debug_hooks.aliased_decl) (alias, decl); +} + +/* Not implemented in VMS Debug. */ + +static void +vmsdbgout_trampoline_decl (tree trampoline, tree decl) +{ + if (write_symbols == VMS_AND_DWARF2_DEBUG) + (*dwarf2_debug_hooks.trampoline_decl) (trampoline, decl); +} + /* Output stuff that Debug requires at the end of every file and generate the VMS Debug debugging info. */ Introduce C++ support in libcc1 Extend libcc1's with an API for C++ support. Extend libcc1's C API to distinguish between integral types with the same width, as in C++. Likewise for float types. Export small bits of functionality from the C++ front-end for use in libcc1. Add support for the C++ front-end to look up names and addresses using a libcc1-registered binding oracle. Add support for global friends. for gcc/cp/ChangeLog Introduce C++ support in libcc1. * cp-tree.h (struct lang_identifier): Add oracle_looked_up. (ansi_litopname): Declare. (add_to_global_friend_list): Declare. (remove_from_global_friend_list): Declare. (is_global_friend): Declare. (enum cp_oracle_request): New type. (cp_binding_oracle_function): New type. (cp_binding_oracle): Declare. (cp_finish_injected_record_type): Declare. * friend.c (global_friend_list): New var. (add_to_global_friend_list): New fn. (find_in_global_friend_list): New fn. (remove_from_global_friend_list): New fn. (is_global_friend): New fn. (is_friend): Call is_global_friend. * name-lookup.c (cp_binding_oracle): New var. (query_oracle): New fn. (qualified_lookup_using_namespace): Call query_oracle. (lookup_name_real_1): Likewise. * parser.c (ansi_litopname): New fn. * search.c (friend_accessible_p): Call is_global_friend. * semantics.c (is_this_parameter): Accept a variable if the binding oracle is enabled. for include Introduce C++ support in libcc1. * gcc-c-fe.def (int_type_v0): Rename from... (int_type): ... this. Introduce new version. (float_type_v0): Rename from... (float_type): ... this. Introduce new version. (char_type): New. * gcc-c-interface.h (gcc_c_api_version): Add GCC_C_FE_VERSION_1. (gcc_type_array): Move... * gcc-interface.h: ... here. * gcc-cp-fe.def: New. * gcc-cp-interface.h: New. for libcc1 Introduce C++ support. * Makefile.am (AM_CPPFLAGS): Move some -I flags to... (CPPFLAGS_FOR_C_FAMILY, CPPFLAGS_FOR_C, CPPFLAGS_FOR_CXX): ... new macros. (plugin_LTLIBRARIES): Add libcp1plugin.la. (BUILT_SOURCES, MOSTLYCLEANFILES): Add... (cp-compiler-name.h): ... this. New. (c-compiler-name.h): Rename all over from... (compiler-name.h): ... this. Create it atomically. (marshall_c_source, marshall_cxx_source): New macros. (libcc1plugin_la_SOURCES): Rename plugin.cc to libcc1plugin.cc. Add marshall_c_source expansion. (libcc1plugin.lo_CPPFLAGS): New macro. (libcp1plugin_la_LDFLAGS): Likewise. (libcp1plugin_la_SOURCES): Likewise. (libcp1plugin.lo_CPPFLAGS): Likewise. (libcp1plugin_la_LIBADD): Likewise. (libcp1plugin_la_DEPENDENCIES): Likewise. (libcp1plugin_la_LINK): Likewise. (libcc1_la_SOURCES): Added marshall_c_source and marshall_cxx_source expansions. * Makefile.in: Rebuild. * compiler-name.h: Rename all over to... * c-compiler-name.h: ... this. Define C_COMPILER_NAME instead of COMPILER_NAME. * plugin.cc: Rename all over to... * libcc1plugin.cc: ... this. Include marshall-c.hh. (address_rewriter): Drop cleaning up of VLA sizes. (plugin_build_decl): Mark decls as external. (plugin_tagbind): Propagate name to all variants. (build_anonymous_node): New. (plugin_build_record_type): Use it instead of make_node. (plugin_build_union_type): Likewise. (plugin_build_enum_type): Likewise. (plugin_finish_record_or_union): Update all type variants. (safe_lookup_builtin_type): New. (plugin_int_check): Factor out of, and add checks to, ... (plugin_int_type): ... this. Rename to... (plugin_int_type_v0): ... this. (plugin_int_type): New interface, new implementation. (plugin_char_type): New. (plugin_float_type_v0): Rename from... (plugin_float_type): ... this. New interface, new implementation. (plugin_init): Bump handshake version. * libcc1.cc: Include marshall-c.hh. Drop gcc-interface.h. (call_binding_oracle): Rename to... (c_call_binding_oracle): ... this, into anonymous namespace. (call_symbol_address): Rename to... (c_call_symbol_address): ... this, likewise. (GCC_METHOD#): Move methods into cc1plugin::c:: namespace. (libcc1::compiler::find): Refer to C_COMPILER_NAME. (fork_exec): Bump to GCC_C_FE_VERSION_1. (libcc1_compile): Prefix callbacks with c_. (gcc_c_fe_context): Accept GCC_C_FE_VERSION_1. * libcc1.sym: Export gcc_cp_fe_context. * libcp1.cc: New, mostly copied and adjusted from libcc1.cc. * libcp1plugin.cc: New, initially copied from libcc1plugin.cc. * libcp1plugin.sym: New. * marshall-c.hh: New. Move C-specific types from... * marshall.cc: ... this. (cc1_plugin::marshall_array_start): New. (cc1_plugin::marshall_array_elmts): New. (cc1_plugin::marshall for gcc_type_array): Use the above. (cc1_plugin::unmarshall_array_start): New. (cc1_plugin::unmarshall_array_elmts): New. (cc1_plugin::unmarshall for gcc_type_array): Use the above. * marshall.hh: Declare the new array building blocks. Drop C-specific unmarshall declarations. * marshall-cp.hh: New. * names.cc (GCC_METHOD#): Add LANG:: to method names. (LANG): Define while including gcc-c-fe.def and gcc-cp-fe.def. * names.hh: Include gcc-c-fe.def and gcc-cp-fe.def in the corresponding namespaces. * rpc.hh: Don't include marshall.hh. [GCC_CP_INTERFACE_H] (argument_wrapper): Specialize for gcc_vbase_array, gcc_cp_template_args, gcc_cp_function_args. --- gcc/cp/cp-tree.h | 29 gcc/cp/friend.c | 63 + gcc/cp/name-lookup.c | 26 gcc/cp/parser.c | 8 gcc/cp/search.c | 3 gcc/cp/semantics.c | 3 include/gcc-c-fe.def | 37 include/gcc-c-interface.h | 23 include/gcc-cp-fe.def | 1018 ++++++++++++ include/gcc-cp-interface.h | 508 ++++++ include/gcc-interface.h | 14 libcc1/Makefile.am | 46 - libcc1/Makefile.in | 68 + libcc1/libcc1.cc | 78 - libcc1/libcc1.sym | 1 libcc1/libcc1plugin.cc | 1020 ++++++++++++ libcc1/libcp1.cc | 706 ++++++++ libcc1/libcp1plugin.cc | 3790 ++++++++++++++++++++++++++++++++++++++++++++ libcc1/libcp1plugin.sym | 2 libcc1/marshall-c.hh | 59 + libcc1/marshall-cp.hh | 271 +++ libcc1/marshall.cc | 111 + libcc1/marshall.hh | 15 libcc1/names.cc | 20 libcc1/names.hh | 18 libcc1/plugin.cc | 921 ----------- libcc1/rpc.hh | 113 + 27 files changed, 7905 insertions(+), 1066 deletions(-) create mode 100644 include/gcc-cp-fe.def create mode 100644 include/gcc-cp-interface.h create mode 100644 libcc1/libcc1plugin.cc create mode 100644 libcc1/libcp1.cc create mode 100644 libcc1/libcp1plugin.cc create mode 100644 libcc1/libcp1plugin.sym create mode 100644 libcc1/marshall-c.hh create mode 100644 libcc1/marshall-cp.hh delete mode 100644 libcc1/plugin.cc diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 2874796..a1dcdb1 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -331,6 +331,7 @@ struct GTY(()) lang_identifier { cxx_binding *bindings; tree class_template_info; tree label_value; + bool oracle_looked_up; }; /* Return a typed pointer version of T if it designates a @@ -1543,6 +1544,7 @@ struct GTY(()) language_function { (operator_name_info[(int) (CODE)].identifier) #define ansi_assopname(CODE) \ (assignment_operator_name_info[(int) (CODE)].identifier) +extern tree ansi_litopname(const char *); /* TRUE if a tree code represents a statement. */ extern bool statement_code_p[MAX_TREE_CODES]; @@ -5957,6 +5959,9 @@ extern int is_friend (tree, tree); extern void make_friend_class (tree, tree, bool); extern void add_friend (tree, tree, bool); extern tree do_friend (tree, tree, tree, tree, enum overload_flags, bool); +extern void add_to_global_friend_list (tree); +extern void remove_from_global_friend_list (tree); +extern bool is_global_friend (tree); /* in init.c */ extern tree expand_member_init (tree); @@ -6856,6 +6861,27 @@ extern void clear_fold_cache (void); extern void suggest_alternatives_for (location_t, tree); extern tree strip_using_decl (tree); +/* Tell the binding oracle what kind of binding we are looking for. */ + +enum cp_oracle_request +{ + CP_ORACLE_SYMBOL, + CP_ORACLE_TAG, + CP_ORACLE_LABEL +}; + +/* If this is non-NULL, then it is a "binding oracle" which can lazily + create bindings when needed by the C compiler. The oracle is told + the name and type of the binding to create. It can call pushdecl + or the like to ensure the binding is visible; or do nothing, + leaving the binding untouched. c-decl.c takes note of when the + oracle has been called and will not call it again if it fails to + create a given binding. */ + +typedef void cp_binding_oracle_function (enum cp_oracle_request, tree identifier); + +extern cp_binding_oracle_function *cp_binding_oracle; + /* in constraint.cc */ extern void init_constraint_processing (); extern bool constraint_p (tree); @@ -6921,6 +6947,9 @@ extern void diagnose_constraints (location_t, tree, tree); extern tree decompose_conclusions (tree); extern bool subsumes (tree, tree); +/* In class.c */ +extern void cp_finish_injected_record_type (tree); + /* in vtable-class-hierarchy.c */ extern void vtv_compute_class_hierarchy_transitive_closure (void); extern void vtv_generate_init_routine (void); diff --git a/gcc/cp/friend.c b/gcc/cp/friend.c index 5e4b2d1..365b1ca 100644 --- a/gcc/cp/friend.c +++ b/gcc/cp/friend.c @@ -24,6 +24,66 @@ along with GCC; see the file COPYING3. If not see /* Friend data structures are described in cp-tree.h. */ + +/* Scopes (functions, classes, or templates) in the TREE_VALUE of + GLOBAL_FRIEND_LIST are regarded as friends of every class. This is + mainly used by libcc1, to enable GDB's code snippets to access + private members without disabling access control in general, which + could cause different template overload resolution results when + accessibility matters (e.g. tests for an accessible member). */ + +static tree global_friend_list; + +/* Add SCOPE to GLOBAL_FRIEND_LIST. The same scope may be added + multiple times, so that matching removals cancel out. */ + +void +add_to_global_friend_list (tree scope) +{ + global_friend_list = tree_cons (NULL_TREE, scope, global_friend_list); +} + +/* Search for SCOPE in the global friend list, and return a pointer to + the first tree cons that matches. The pointer can be used to + modify the list. + + A match means the TREE_VALUE is SCOPE or, if an EXACT match is not + required, a template that has SCOPE as a specialization. */ + +static inline tree * +find_in_global_friend_list (tree scope, bool exact) +{ + for (tree *p = &global_friend_list; + *p; p = &TREE_CHAIN (*p)) + if (TREE_VALUE (*p) == scope + || (!exact + && is_specialization_of_friend (TREE_VALUE (*p), scope))) + return p; + + return NULL; +} + +/* Remove one occurrence of SCOPE from the global friend list. + There must be at least one such occurrence. */ + +void +remove_from_global_friend_list (tree scope) +{ + tree *p = find_in_global_friend_list (scope, true); + + gcc_assert (p); + + *p = TREE_CHAIN (*p); +} + +/* Return TRUE if SCOPE is in the global friend list. */ + +bool +is_global_friend (tree scope) +{ + return !!find_in_global_friend_list (scope, false); +} + /* Returns nonzero if SUPPLICANT is a friend of TYPE. */ int @@ -36,6 +96,9 @@ is_friend (tree type, tree supplicant) if (supplicant == NULL_TREE || type == NULL_TREE) return 0; + if (is_global_friend (supplicant)) + return 1; + declp = DECL_P (supplicant); if (declp) diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index ce16d57..ff9c767 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -88,6 +88,27 @@ get_anonymous_namespace_name (void) static GTY((deletable)) binding_entry free_binding_entry = NULL; +/* The binding oracle; see cp-tree.h. */ + +cp_binding_oracle_function *cp_binding_oracle; + +/* If we have a binding oracle, ask it for all namespace-scoped + definitions of NAME. */ + +static inline void +query_oracle (tree name) +{ + // FIXME: we need a more space-efficient representation for + // oracle_looked_up. + if (cp_binding_oracle && !LANG_IDENTIFIER_CAST (name)->oracle_looked_up) + { + LANG_IDENTIFIER_CAST (name)->oracle_looked_up = true; + // FIXME: unify CP_ORACLE_SYMBOL and CP_ORACLE_TAG for C++. + cp_binding_oracle (CP_ORACLE_SYMBOL, name); + cp_binding_oracle (CP_ORACLE_TAG, name); + } +} + /* Create a binding_entry object for (NAME, TYPE). */ static inline binding_entry @@ -4626,6 +4647,8 @@ qualified_lookup_using_namespace (tree name, tree scope, /* Look through namespace aliases. */ scope = ORIGINAL_NAMESPACE (scope); + query_oracle (name); + /* Algorithm: Starting with SCOPE, walk through the set of used namespaces. For each used namespace, look through its inline namespace set for any bindings and usings. If no bindings are @@ -4942,6 +4965,8 @@ lookup_name_real_1 (tree name, int prefer_type, int nonclass, bool block_p, cxx_binding *iter; tree val = NULL_TREE; + query_oracle (name); + /* Conversion operators are handled specially because ordinary unqualified name lookup will not find template conversion operators. */ @@ -6153,6 +6178,7 @@ pushtag (tree name, tree type, tag_scope scope) timevar_cond_stop (TV_NAME_LOOKUP, subtime); return ret; } + /* Subroutines for reverting temporarily to top-level for instantiation of templates and such. We actually need to clear out the class- and diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 168486c..f9b02e9 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -13869,6 +13869,14 @@ cp_literal_operator_id (const char* name) return identifier; } +/* Exported wrapper for cp_literal_operator_id. */ + +tree +ansi_litopname (const char *name) +{ + return cp_literal_operator_id (name); +} + /* Parse an operator. operator: diff --git a/gcc/cp/search.c b/gcc/cp/search.c index 325ef98..2b26df4 100644 --- a/gcc/cp/search.c +++ b/gcc/cp/search.c @@ -782,6 +782,9 @@ friend_accessible_p (tree scope, tree decl, tree type, tree otype) if (!scope) return 0; + if (is_global_friend (scope)) + return 1; + /* Is SCOPE itself a suitable P? */ if (TYPE_P (scope) && protected_accessible_p (decl, scope, type, otype)) return 1; diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index e415732..9c8e1f3 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -9263,7 +9263,8 @@ is_this_parameter (tree t) { if (!DECL_P (t) || DECL_NAME (t) != this_identifier) return false; - gcc_assert (TREE_CODE (t) == PARM_DECL || is_capture_proxy (t)); + gcc_assert (TREE_CODE (t) == PARM_DECL || is_capture_proxy (t) + || (cp_binding_oracle && TREE_CODE (t) == VAR_DECL)); return true; } diff --git a/include/gcc-c-fe.def b/include/gcc-c-fe.def index 25ace1c..289e6a0 100644 --- a/include/gcc-c-fe.def +++ b/include/gcc-c-fe.def @@ -1,6 +1,6 @@ /* Interface between GCC C FE and GDB -*- c -*- - Copyright (C) 2014-2015 Free Software Foundation, Inc. + Copyright (C) 2014-2016 Free Software Foundation, Inc. This file is part of GCC. @@ -125,16 +125,18 @@ GCC_METHOD3 (gcc_type, build_function_type, const struct gcc_type_array *, /* Argument ARGUMENT_TYPES. */ int /* bool */) /* Argument IS_VARARGS. */ -/* Return an integer type with the given properties. */ +/* Return an integer type with the given properties. + Deprecated in v1, use int_type instead. */ -GCC_METHOD2 (gcc_type, int_type, +GCC_METHOD2 (gcc_type, int_type_v0, int /* bool */, /* Argument IS_UNSIGNED. */ unsigned long) /* Argument SIZE_IN_BYTES. */ -/* Return a floating point type with the given properties. */ +/* Return a floating point type with the given properties. + Deprecated in v1, use float_type instead. */ -GCC_METHOD1 (gcc_type, float_type, - unsigned long) /* Argument SIZE_IN_BYTES. */ +GCC_METHOD1 (gcc_type, float_type_v0, + unsigned long) /* Argument SIZE_IN_BYTES. */ /* Return the 'void' type. */ @@ -195,3 +197,26 @@ GCC_METHOD5 (int /* bool */, build_constant, GCC_METHOD1 (gcc_type, error, const char *) /* Argument MESSAGE. */ + +/* Return an integer type with the given properties. If BUILTIN_NAME + is non-NULL, it must name a builtin integral type with the given + signedness and size, and that is the type that will be returned. */ + +GCC_METHOD3 (gcc_type, int_type, + int /* bool */, /* Argument IS_UNSIGNED. */ + unsigned long, /* Argument SIZE_IN_BYTES. */ + const char *) /* Argument BUILTIN_NAME. */ + +/* Return the 'char' type, a distinct type from both 'signed char' and + 'unsigned char' returned by int_type. */ + +GCC_METHOD0 (gcc_type, char_type) + +/* Return a floating point type with the given properties. If BUILTIN_NAME + is non-NULL, it must name a builtin integral type with the given + signedness and size, and that is the type that will be returned. */ + +GCC_METHOD2 (gcc_type, float_type, + unsigned long, /* Argument SIZE_IN_BYTES. */ + const char *) /* Argument BUILTIN_NAME. */ + diff --git a/include/gcc-c-interface.h b/include/gcc-c-interface.h index 95d0fc9..24a933b 100644 --- a/include/gcc-c-interface.h +++ b/include/gcc-c-interface.h @@ -1,6 +1,6 @@ /* Interface between GCC C FE and GDB - Copyright (C) 2014-2015 Free Software Foundation, Inc. + Copyright (C) 2014-2016 Free Software Foundation, Inc. This file is part of GCC. @@ -41,7 +41,11 @@ struct gcc_c_context; enum gcc_c_api_version { - GCC_C_FE_VERSION_0 = 0 + GCC_C_FE_VERSION_0 = 0, + + /* Added char_type. Added new version of int_type and float_type, + deprecated int_type_v0 and float_type_v0. */ + GCC_C_FE_VERSION_1 = 1 }; /* Qualifiers. */ @@ -111,19 +115,6 @@ typedef gcc_address gcc_c_symbol_address_function (void *datum, struct gcc_c_context *ctxt, const char *identifier); -/* An array of types used for creating a function type. */ - -struct gcc_type_array -{ - /* Number of elements. */ - - int n_elements; - - /* The elements. */ - - gcc_type *elements; -}; - /* The vtable used by the C front end. */ struct gcc_c_fe_vtable @@ -146,7 +137,7 @@ struct gcc_c_fe_vtable provides the declaration. DATUM is an arbitrary piece of data that is passed back verbatim - to the callbakcs in requests. */ + to the callbacks in requests. */ void (*set_callbacks) (struct gcc_c_context *self, gcc_c_oracle_function *binding_oracle, diff --git a/include/gcc-cp-fe.def b/include/gcc-cp-fe.def new file mode 100644 index 0000000..102bd32 --- /dev/null +++ b/include/gcc-cp-fe.def @@ -0,0 +1,1018 @@ +/* Interface between GCC C++ FE and GDB -*- c -*- + + Copyright (C) 2014-2016 Free Software Foundation, Inc. + + This file is part of GCC. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + + + +/* Push namespace NAME as the current binding level, to which + newly-introduced decls will be bound. An empty string identifies + the global namespace, whereas NULL identifies an anonymous + namespace. A namespace named NAME is created in the current scope, + if needed. + + If the newly-created namespace is to be an inline namespace, after + push_namespace, get the nested namespace decl with + get_current_binding_level, pop back to the enclosing namespace, + call using_namespace with INLINE_P, and then push to the inline + namespace again. */ + +GCC_METHOD1 (int /* bool */, push_namespace, + const char *) /* Argument NAME. */ + +/* Push TYPE as the current binding level, making its members visible + for name lookup. The current scope before the call must be the + scope in which the class was declared. This should be used if the + definition of a class is already finished, but one wishes to define + a nested class, or to enter the scope of one of its member + functions. */ + +GCC_METHOD1 (int /* bool */, push_class, + gcc_type) /* Argument TYPE. */ + +/* Push FUNCTION_DECL as the current (empty) binding level (see + reactivate_decl). The current enclosing scope before the call must + be the scope in which the function was declared. */ + +GCC_METHOD1 (int /* bool */, push_function, + gcc_decl) /* Argument FUNCTION_DECL. */ + +/* Make DECL visible (again?) within SCOPE. When SCOPE is NULL, it + means the current scope; if it is not NULL, it must name a function + that is currently active, even if not at the top of the binding + chain. + + This function can be used to make e.g. a global function or + variable visible in a namespace or local scope (overriding another + enclosing definition of the same name), but its most common + expected use of this primitive, that gives it its name, is to make + declarations visible again after reentering a function scope, + because when a function is entered with push_function, that does + NOT make any of the declarations nested in it visible for name + lookup. + + There is a reason/excuse for that: unlike namespaces and classes, + G++ doesn't ever have to reenter function scopes, so its name + resolution infrastructure is not prepared to do that. But wait, + there is also a good use for this apparent limitation: a function + may contain multiple scopes (blocks), and the name may be bound to + different symbols in each of these scopes. With this interface, as + we reenter a function scope, we may choose which symbols to make + visible for the code snippet, or, if there could be template + functions in local scopes, for unresolved names in nested template + class default arguments, or in nested template function signatures. + + As for making a local declaration visible for the code snippet, + there are two possibilities: a) introduce it upfront, while + entering the scope for the user expression (see the enter_scope + callback, called by g++ when encountering the push_user_expression + pragma), which might save some scope switching and reactivate_decl + (though this can't be helped if some declarations have to be + introduced and discarded, because of multiple definitions of the + same name in different scopes within a function: they have to be + defined in discriminator order); or b) introduce it when its name + is looked up, entering the scope, introducing the declaration, + leaving the scope, and then reactivating the declaration in its + local scope. + + Here's some more detail on how reactivate_decl works. Say there's + a function foo whose body looks like this: + + { + { +// point 1 + class c {} o __attribute__ ((__used__)); // c , o + } + struct c { + void f() { +// point 2 + } + } o __attribute__ ((__used__)); // c_0, o_0 + { + class c {} p __attribute__ ((__used__)); // c_1, p +// point 3 + o.f(); + } + } + + When we are about to define class c at point 1, we enter the + function foo scope, and since no symbols are visible at point 1, we + proceed to declare class c. We may then define the class right + away, or, if we leave the function scope, and we later wish to + define it, or to define object o, we can reenter the scope and just + use the previously-obtained gcc_decl to define the class, without + having to reactivate the declaration. + + Now, if we are to set up the binding context for point 2, we have + to define c_0::f, and in order to do so, we have to declare and + define c_0. Before we can declare c_0, we MUST at least declare c. + + As a general rule, before we can declare or define any local name + with a discriminator, we have to at least declare any other + occurrences of the same name in the same enclosing entity with + lower or absent discriminator. + + So, we declare c, then we leave the function scope and reenter it + so as to declare c_0 (also with name "c", which is why we have to + leave and reenter the function scope, otherwise we would get an + error because of the duplicate definition; g++ will assign a + discriminator because it still remembers there was an earlier + declaration of c_0 within the function, it's just no longer in + scope), then we can define c_0, including its member function f. + + Likewise, if we wish to define o_0, we have to define o first. If + we wish to declare (and maybe then define) c_1, we have to at least + declare (c and then) c_0 first. + + Then, as we set up the binding context to compile a code snippet at + point 3, we may choose to activate c_1, o_0 and p upfront, + declaring and discarding c, c_0 and o, and then reentering the + funciton scope to declare c_1, o_0 and p; or we can wait for oracle + lookups of c, o or p. If c is looked up, and the debugger resolves + c in the scope to c_1, it is expected to enter the function scope + from the top level, declare c, leave it, reenter it, declare c_0, + leave it, reenter it, declare c_1, leave it, and then reactivate + c_1 in the function scope. If c_1 is needed as a complete type, + the definition may be given right after the declaration, or the + scope will have to be reentered in order to define the class. + +. If the code snippet is at point 2, we don't need to (re)activate + anything declaration: nothing from any local scope is visible. + Just entering the scope of the class containing member function f + reactivates the names of its members, including the class name + itself. */ + +GCC_METHOD2 (int /* bool */, reactivate_decl, + gcc_decl, /* Argument DECL. */ + gcc_decl) /* Argument SCOPE. */ + +/* Pop the namespace last entered with push_namespace, or class last + entered with push_class, or function last entered with + push_function, restoring the binding level in effect before the + matching push_* call. */ + +GCC_METHOD0 (int /* bool */, pop_namespace) + +/* Return the NAMESPACE_DECL, TYPE_DECL or FUNCTION_DECL of the + binding level that would be popped by pop_namespace. */ + +GCC_METHOD0 (gcc_decl, get_current_binding_level) + +/* Add USED_NS to the namespaces used by the current binding level. + Use get_current_binding_level to obtain USED_NS's gcc_decl. + INLINE_P indicates USED_NS was declared as an inline namespace, or + the presence of attribute strong in the using directive, which + is an older but equivalent GCC extension. */ + +GCC_METHOD2 (int /* bool */, using_namespace, + gcc_decl, /* Argument USED_NS. */ + int /* bool */) /* Argument INLINE_P. */ + +/* Introduce a namespace alias declaration, as in: + + namespace foo = [... ::] bar; + + After this call, namespace TARGET will be visible as ALIAS within + the current namespace. Get the declaration for TARGET by calling + get_current_binding_level after pushing into it. */ + +GCC_METHOD2 (int /* bool */, new_namespace_alias, + const char *, /* Argument ALIAS. */ + gcc_decl) /* Argument TARGET. */ + +/* Introduce a using declaration, as in: + + using foo::bar; + + The TARGET decl names the qualifying scope (foo:: above) and the + identifier (bar), but that does not mean that only TARGET will be + brought into the current scope: all bindings of TARGET's identifier + in the qualifying scope will be brought in. + + FLAGS should specify GCC_CP_SYMBOL_USING. If the current scope is + a class scope, visibility flags must be supplied. + + Even when TARGET is template dependent, we don't need to specify + whether or not it is a typename: the supplied declaration (that + could be a template-dependent type converted to declaration by + type_decl) indicates so. */ + +GCC_METHOD2 (int /* bool */, new_using_decl, + enum gcc_cp_symbol_kind, /* Argument FLAGS. */ + gcc_decl) /* Argument TARGET. */ + +/* Create a new "decl" in GCC, and bind it in the current binding + level. A decl is a declaration, basically a kind of symbol. + + NAME is the name of the new symbol. SYM_KIND is the kind of + symbol being requested. SYM_TYPE is the new symbol's C++ type; + except for labels, where this is not meaningful and should be + zero. If SUBSTITUTION_NAME is not NULL, then a reference to this + decl in the source will later be substituted with a dereference + of a variable of the given name. Otherwise, for symbols having + an address (e.g., functions), ADDRESS is the address. FILENAME + and LINE_NUMBER refer to the symbol's source location. If this + is not known, FILENAME can be NULL and LINE_NUMBER can be 0. + This function returns the new decl. + + Use this function to register typedefs, functions and variables to + namespace and local binding levels, and typedefs, member functions + (static or not), and static data members to class binding levels. + Note that, since access controls are disabled, we have no means to + express private, protected and public. + + There are various flags that can be set in SYM_KIND to specify + additional semantics. Look for GCC_CP_FLAGs in the definition of + enum gcc_cp_symbol_kind in gcc-cp-interface.h. + + In order to define member functions, pass GCC_CP_SYMBOL_FUNCTION in + SYM_KIND, and a function_type for static member functions or a + method type for non-static member functions, including constructors + and destructors. Use build_function_type to create a function + type; for a method type, start by creating a function type without + any compiler-introduced artificial arguments (the implicit this + pointer, and the __in_chrg added to constructors and destructors, + and __vtt_parm added to the former), and then use build_method_type + to create the method type out of the class type and the function + type. + + For operator functions, set GCC_CP_FLAG_SPECIAL_FUNCTION in + SYM_KIND, in addition to any other applicable flags, and pass as + NAME a string starting with the two-character mangling for operator + name: "ps" for unary plus, "mL" for multiply and assign, *=; etc. + Use "cv" for type converstion operators (the target type portion + may be omitted, as it is taken from the return type in SYM_TYPE). + For operator"", use "li" followed by the identifier (the mangled + name mandates digits specifying the length of the identifier; if + present, they determine the end of the identifier, otherwise, the + identifier extents to the end of the string, so that "li3_Kme" and + "li_Km" are equivalent). + + Constructors and destructors need special care, because for each + constructor and destructor there may be multiple clones defined + internally by the compiler. With new_decl, you can introduce the + base declaration of a constructor or a destructor, setting + GCC_CP_FLAG_SPECIAL_FUNCTION the flag and using names starting with + capital "C" or "D", respectively, followed by a digit (see below), + a blank, or NUL ('\0'). DO NOT supply an ADDRESS or a + SUBSTITUTION_NAME to new_decl, it would be meaningless (and + rejected) for the base declaration; use define_cdtor_clone to + introduce the address of each clone. For constructor templates, + declare the template with new_decl, and then, for each + specialization, introduce it with specialize_function_template, and + then define the addresses of each of its clones with + define_cdtor_clone. + + NAMEs for GCC_CP_FLAG_SPECIAL_FUNCTION: + + NAME meaning + C? constructor base declaration (? may be 1, 2, 4, blank or NUL) + D? destructor base declaration (? may be 0, 1, 2, 4, blank or NUL) + nw operator new + na operator new[] + dl operator delete + da operator delete[] + ps operator + (unary) + ng operator - (unary) + ad operator & (unary) + de operator * (unary) + co operator ~ + pl operator + + mi operator - + ml operator * + dv operator / + rm operator % + an operator & + or operator | + eo operator ^ + aS operator = + pL operator += + mI operator -= + mL operator *= + dV operator /= + rM operator %= + aN operator &= + oR operator |= + eO operator ^= + ls operator << + rs operator >> + lS operator <<= + rS operator >>= + eq operator == + ne operator != + lt operator < + gt operator > + le operator <= + ge operator >= + nt operator ! + aa operator && + oo operator || + pp operator ++ + mm operator -- + cm operator , + pm operator ->* + pt operator -> + cl operator () + ix operator [] + qu operator ? + cv operator (conversion operator) + li operator "" + + FIXME: How about attributes? */ + +GCC_METHOD7 (gcc_decl, new_decl, + const char *, /* Argument NAME. */ + enum gcc_cp_symbol_kind, /* Argument SYM_KIND. */ + gcc_type, /* Argument SYM_TYPE. */ + const char *, /* Argument SUBSTITUTION_NAME. */ + gcc_address, /* Argument ADDRESS. */ + const char *, /* Argument FILENAME. */ + unsigned int) /* Argument LINE_NUMBER. */ + +/* Supply the ADDRESS of one of the multiple clones of constructor or + destructor CDTOR. The clone is selected using the following + name mangling conventions: + + C1 in-charge constructor + C2 not-in-charge constructor + C4 unified constructor + D0 deleting destructor + D1 in-charge destructor + D2 not-in-charge destructor + D4 unified destructor + + The following information is not necessary to use the API. + + C1 initializes an instance of the class (rather than of derived + classes), including virtual base classes, whereas C2 initializes a + sub-object (of the given class type) of an instance of some derived + class (or a full object that doesn't have any virtual base + classes). + + D0 and D1 destruct an instance of the class, including virtual base + classes, but only the former calls operator delete to release the + object's storage at the end; D2 destructs a sub-object (of the + given class type) of an instance of a derived class (or a full + object that doesn't have any virtual base classes). + + The [CD]4 manglings (and symbol definitions) are non-standard, but + GCC uses them in some cases: rather than assuming they are + in-charge or not-in-charge, they test the implicit argument that + the others ignore to tell how to behave. These are defined in very + rare cases of virtual inheritance and cdtor prototypes. */ + +GCC_METHOD3 (gcc_decl, define_cdtor_clone, + const char *, /* Argument NAME. */ + gcc_decl, /* Argument CDTOR. */ + gcc_address) /* Argument ADDRESS. */ + +/* Return the type associated with the given declaration. This is + most useful to obtain the type associated with a forward-declared + class, because it is the gcc_type, rather than the gcc_decl, that + has to be used to build other types, but new_decl returns a + gcc_decl rather than a gcc_type. This call can in theory be used + to obtain the type from any other declaration; it is supposed to + return the same type that was supplied when the declaration was + created. */ + +GCC_METHOD1 (gcc_type, decl_type, + gcc_decl) /* Argument DECL. */ + +/* Return the declaration for a type. */ + +GCC_METHOD1 (gcc_decl, type_decl, + gcc_type) /* Argument TYPE. */ + +/* Declare DECL as a friend of the current class scope, if TYPE is + NULL, or of TYPE itself otherwise. DECL may be a function or a + class, be they template generics, template specializations or not + templates. TYPE must be a class type (not a template generic). + + The new_friend call cannot introduce a declaration; even if the + friend is first declared as a friend in the source code, the + declaration belongs in the enclosing namespace, so it must be + introduced in that namespace, and the resulting declaration can + then be made a friend. + + DECL cannot, however, be a member of a template class generic, + because we have no means to introduce their declarations. This + interface has no notion of definitions for template generics. As a + consequence, users of this interface must introduce each friend + template member specialization separately, i.e., instead of: + + template friend struct X::M; + + they must be declared as if they were: + + friend struct X::M; + friend struct X::M; + ... for each specialization of X. + + + Specializations of a template can have each others' members as + friends: + + template class foo { + int f(); + template friend int foo::f(); + }; + + It wouldn't always be possible to define all specializations of a + template class before introducing the friend declarations in their + expanded, per-specialization form. + + In order to simplify such friend declarations, and to enable + incremental friend declarations as template specializations are + introduced, new_friend can be called after the befriended class is + fully defined, passing it a non-NULL TYPE argument naming the + befriended class type. */ + +GCC_METHOD2 (int /* bool */, new_friend, + gcc_decl, /* Argument DECL. */ + gcc_type) /* Argument TYPE. */ + +/* Return the type of a pointer to a given base type. */ + +GCC_METHOD1 (gcc_type, build_pointer_type, + gcc_type) /* Argument BASE_TYPE. */ + +/* Return the type of a reference to a given base type. */ + +GCC_METHOD2 (gcc_type, build_reference_type, + gcc_type, /* Argument BASE_TYPE. */ + enum gcc_cp_ref_qualifiers) /* Argument RQUALS. */ + +/* Create a new pointer-to-member type. MEMBER_TYPE is the data + member type, while CLASS_TYPE is the class type containing the data + member. For pointers to member functions, MEMBER_TYPE must be a + method type, and CLASS_TYPE must be specified even though it might + be possible to extract it from the method type. */ + +GCC_METHOD2 (gcc_type, build_pointer_to_member_type, + gcc_type, /* Argument CLASS_TYPE. */ + gcc_type) /* Argument MEMBER_TYPE. */ + +/* Start a template parameter list scope and enters it, so that + subsequent build_template_typename_parm and + build_template_value_parm calls create template parameters in the + list. The list is closed by a new_decl call with + GCC_CP_SYMBOL_FUNCTION or GCC_CP_SYMBOL_CLASS, that, when the scope + is a template parameter list, declares a template function or a + template class with the then-closed parameter list. The scope in + which the new declaration is to be introduced by new_decl must be + entered before calling start_new_template_decl, and new_decl + returns to that scope, from the template parameter list scope, + before introducing the declaration. */ + +GCC_METHOD0 (int /* bool */, start_new_template_decl) + +/* Build a typename template-parameter (e.g., the T in template + ). Either PACK_P should be nonzero, to indicate an + argument pack (the last argument in a variadic template argument + list, as in template ), or DEFAULT_TYPE may be + non-NULL to set the default type argument (e.g. X) for the template + parameter. FILENAME and LINE_NUMBER may specify the source + location in which the template parameter was declared. */ + +GCC_METHOD5 (gcc_type, new_template_typename_parm, + const char *, /* Argument ID. */ + int /* bool */, /* Argument PACK_P. */ + gcc_type, /* Argument DEFAULT_TYPE. */ + const char *, /* Argument FILENAME. */ + unsigned int) /* Argument LINE_NUMBER. */ + +/* Build a template template-parameter (e.g., the T in template +