diff options
Diffstat (limited to 'gcc-4.8.1/gcc/go')
53 files changed, 0 insertions, 67354 deletions
diff --git a/gcc-4.8.1/gcc/go/ChangeLog b/gcc-4.8.1/gcc/go/ChangeLog deleted file mode 100644 index 57ce2530f..000000000 --- a/gcc-4.8.1/gcc/go/ChangeLog +++ /dev/null @@ -1,590 +0,0 @@ -2013-05-31 Release Manager - - * GCC 4.8.1 released. - -2013-03-22 Release Manager - - * GCC 4.8.0 released. - -2013-01-16 Shenghou Ma <minux.ma@gmail.com> - - * gospec.c: pass -u pthread_create to linker when static linking. - -2012-12-21 Ian Lance Taylor <iant@google.com> - - PR bootstrap/54659 - * go-system.h: Don't include <cstdio>. - -2012-12-18 Ian Lance Taylor <iant@google.com> - - PR go/55201 - * gospec.c: Revert last patch. - -2012-12-18 Andreas Schwab <schwab@linux-m68k.org> - - PR go/55201 - * gospec.c (LIBATOMIC): Define. - (LIBATOMIC_PROFILE): Define. - (lang_specific_driver): Add LIBATOMIC[_PROFILE] option. - -2012-11-29 Ian Lance Taylor <iant@google.com> - - * go-gcc.cc: Include "output.h". - (global_variable): Add is_unique_section parameter. - (global_variable_set_init): Adjust unique section if necessary. - * Make-lang.in (go/go-gcc.o): Add dependency on output.h. - -2012-11-17 Diego Novillo <dnovillo@google.com> - - Adjust for new vec API (http://gcc.gnu.org/wiki/cxx-conversion/cxx-vec) - - * go-lang.c: Use new vec API in vec.h. - -2012-11-16 Ian Lance Taylor <iant@google.com> - - * Make-lang.in (gccgo$(exeext)): Add + at start of command. - (go1$(exeext)): Likewise. - -2012-10-30 Ian Lance Taylor <iant@google.com> - - * lang.opt (-fgo-relative-import-path): New option. - * go-lang.c (go_relative_import_path): New static variable. - (go_langhook_init): Pass go_relative_import_path to - go_create_gogo. - (go_langhook_handle_option): Handle -fgo-relative-import-path. - * go-c.h (go_create_gogo): Update declaration. - * gccgo.texi (Invoking gccgo): Document - -fgo-relative-import-path. - -2012-09-17 Ian Lance Taylor <iant@google.com> - - * config-lang.in (target_libs): Add target-libbacktrace. - -2012-09-16 Ian Lance Taylor <iant@google.com> - - * Make-lang.in (go/gogo.o): Depend on filenames.h. - -2012-08-14 Diego Novillo <dnovillo@google.com> - - Merge from cxx-conversion branch. Configury. - - * go-c.h: Remove all handlers of ENABLE_BUILD_WITH_CXX. - * go-gcc.cc: Likewise. - * go-system.h: Likewise. - -2012-07-24 Uros Bizjak <ubizjak@gmail.com> - - * go-lang.c (lang_decl): Add variable_size GTY option. - -2012-05-09 Ian Lance Taylor <iant@google.com> - - * lang.opt: Add -fgo-pkgpath. - * go-lang.c (go_pkgpath): New static variable. - (go_prefix): New static variable. - (go_langhook_init): Pass go_pkgpath and go_prefix to - go_create_gogo. - (go_langhook_handle_option): Handle -fgo-pkgpath. Change - -fgo-prefix handling to just set go_prefix. - * go-c.h (go_set_prefix): Don't declare. - (go_create_gogo): Add pkgpath and prefix to declaration. - * go-gcc.cc (Gcc_backend::global_variable): Change unique_prefix - to pkgpath. Don't include the package name in the asm name. - * gccgo.texi (Invoking gccgo): Document -fgo-pkgpath. Update the - docs for -fgo-prefix. - -2012-04-23 Ian Lance Taylor <iant@google.com> - - * go-lang.c (go_langhook_init): Set MPFR precision to 256. - -2012-04-20 Ian Lance Taylor <iant@google.com> - - * lang.opt: Add -fgo-check-divide-zero and - -fgo-check-divide-overflow. - * gccgo.texi (Invoking gccgo): Document new options. - -2012-04-18 Steven Bosscher <steven@gcc.gnu.org> - - * go-gcc.cc (Gcc_backend::switch_statement): Build SWITCH_EXPR - with NULL_TREE type instead of void_type_node. - -2012-03-09 Ian Lance Taylor <iant@google.com> - - * go-gcc.cc (Gcc_backend::assignment_statement): Convert the rhs - to the lhs type if necessary. - -2012-03-08 Ian Lance Taylor <iant@google.com> - - * go-gcc.cc (Gcc_backend::init_statement): Don't initialize a - zero-sized variable. - (go_non_zero_struct): New global variable. - (Gcc_backend::non_zero_size_type): New function. - (Gcc_backend::global_variable): Don't build an assignment for a - zero-sized value. - * go-c.h (go_non_zero_struct): Declare. - * config-lang.in (gtfiles): Add go-c.h. - -2012-02-29 Ian Lance Taylor <iant@google.com> - - * go-gcc.cc (class Gcc_tree): Add set_tree method. - (set_placeholder_pointer_type): When setting to a pointer to - error, set to error_mark_node. - -2012-02-23 Richard Guenther <rguenther@suse.de> - - * go-gcc.cc (Gcc_backend::placeholder_pointer_type): Use - build_distinct_type_copy. - -2012-02-17 Ian Lance Taylor <iant@google.com> - - * Make-lang.in (go/import.o): Add dependency on $(GO_LEX_H). - -2012-02-17 Ian Lance Taylor <iant@google.com> - - * gospec.c (lang_specific_driver): If linking, and no -o option - was used, add one. - -2012-02-14 Ian Lance Taylor <iant@google.com> - - PR go/48411 - * Make-lang.in (gccgo-cross$(exeext)): New target. - (go.all.cross): Depend on gccgo-cross$(exeext) instead of - gccgo$(exeext). - (go.install-common): Only install GCCGO_TARGET_INSTALL_NAME if - gccgo-cross$(exeext) does not exist. - -2012-02-07 Ian Lance Taylor <iant@google.com> - - * gccgo.texi (Function Names): Document //extern instead of - __asm__. - -2012-02-01 Jakub Jelinek <jakub@redhat.com> - - PR target/52079 - * go-lang.c (go_langhook_type_for_mode): For TImode and 64-bit HWI - return build_nonstandard_integer_type result if possible. - -2012-01-21 Ian Lance Taylor <iant@google.com> - - * go-gcc.cc (Gcc_backend::type_size): Check for error_mark_node. - (Gcc_backend::type_alignment): Likewise. - (Gcc_backend::type_field_alignment): Likewise. - (Gcc_backend::type_field_offset): Likewise. - -2012-01-20 Ian Lance Taylor <iant@google.com> - - * go-gcc.cc (Gcc_backend::placeholder_struct_type): Permit name to - be empty. - (Gcc_backend::set_placeholder_struct_type): Likewise. - -2012-01-17 Ian Lance Taylor <iant@google.com> - - * gospec.c (lang_specific_driver): If we see -S without -o, add -o - BASE.s rather than -o BASE.o. - -2012-01-11 Ian Lance Taylor <iant@google.com> - - * go-lang.c (go_langhook_init): Initialize void_list_node before - calling go_create_gogo. - -2012-01-10 Ian Lance Taylor <iant@google.com> - - * go-gcc.cc (Gcc_backend::type_size): New function. - (Gcc_backend::type_alignment): New function. - (Gcc_backend::type_field_alignment): New function. - (Gcc_backend::type_field_offset): New function. - * go-backend.c (go_type_alignment): Remove. - * go-c.h (go_type_alignment): Don't declare. - -2011-12-27 Ian Lance Taylor <iant@google.com> - - * go-gcc.cc (Gcc_backend::set_placeholder_struct_type): Use - build_distinct_type_copy rather than build_variant_type_copy. - (Gcc_backend::set_placeholder_array_type): Likewise. - (Gcc_backend::named_type): Add special handling for builtin - basic types. - -2011-12-22 Ian Lance Taylor <iant@google.com> - - * go-gcc.cc (Gcc_backend::set_placeholder_pointer_type): Arrange - for the type name to have a DECL_ORIGINAL_TYPE as gcc expects. - (Gcc_backend::set_placeholder_struct_type): Likewise. - (Gcc_backend::set_placeholder_array_type): Likewise. - (Gcc_backend::named_type): Set DECL_ORIGINAL_TYPE. - -2011-12-13 Ian Lance Taylor <iant@google.com> - - * go-backend.c: #include "simple-object.h" and "intl.h". - (GO_EXPORT_SEGMENT_NAME): Define if not defined. - (GO_EXPORT_SECTION_NAME): Likewise. - (go_write_export_data): Use GO_EXPORT_SECTION_NAME. - (go_read_export_data): New function. - * go-c.h (go_read_export_data): Declare. - -2011-11-29 Sanjoy Das <thedigitalangel@gmail.com> - Ian Lance Taylor <iant@google.com> - - * go-location.h: New file. - * go-linemap.cc: New file. - * go-gcc.cc: Change all uses of source_location to Location. - * Make-lang.in (GO_OBJS): Add go/go-linemap.o. - (GO_LINEMAP_H): New variable. - (GO_LEX_H): Use $(GO_LINEMAP_H). - (GO_GOGO_H, GO_TYPES_H, GO_IMPORT_H): Likewise. - (go/go-linemap.o): New target. - -2011-11-02 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> - - * Make-lang.in (gospec.o): Pass SHLIB instead of SHLIB_LINK. - -2011-08-24 Roberto Lublinerman <rluble@gmail.com> - - * lang.opt: Add fgo-optimize-. - * go-lang.c (go_langhook_handle_option): Handle OPT_fgo_optimize. - * go-c.h (go_enable_optimize): Declare. - * Make-lang.in (GO_OBJS): Add go/go-optimize.o. - (GO_EXPORT_H): Define. - (GO_IMPORT_H): Add $(GO_EXPORT_H). - (GO_AST_DUMP_H): Define. - (go/ast-dump.o, go/statements.o): Use GO_AST_DUMP_H. - (go/export.o, go/gogo.o, go/import.o): Use GO_EXPORT_H. - (go/types.o): Likewise. - (go/expressions.o): Use GO_AST_DUMP_H and GO_EXPORT_H. - (go/go-optimize.o): New target. - -2011-08-24 Joseph Myers <joseph@codesourcery.com> - - * Make-lang.in (CFLAGS-go/go-lang.o): New. - (go/go-lang.o): Remove explicit compilation rule. - -2011-08-08 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> - - * Make-lang.in (gccgo$(exeext)): Add $(EXTRA_GCC_LIBS). - -2011-08-02 Roberto Lublinerman <rluble@gmail.com> - - * Make-lang.in (GO_OBJS): Add go/ast-dump.o. - (go/ast-dump.o): New target. - (go/expressions.o): Depend on go/gofrontend/ast-dump.h. - (go/statements.o): Likewise. - -2011-07-06 Richard Guenther <rguenther@suse.de> - - * go-lang.c (go_langhook_init): - Merge calls to build_common_tree_nodes and build_common_tree_nodes_2. - -2011-06-14 Joseph Myers <joseph@codesourcery.com> - - * Make-lang.in (go/go-lang.o, go/go-backend.o): Update - dependencies. - * go-backend.c: Include common/common-target.h. - (go_write_export_data): Use targetm_common.have_named_sections. - * go-lang.c: Include common/common-target.h. - (go_langhook_init_options_struct): Use - targetm_common.supports_split_stack. - -2011-06-13 Ian Lance Taylor <iant@google.com> - - * Make-lang.in (go/expressions.o): Depend on $(GO_RUNTIME_H). - -2011-06-10 Ian Lance Taylor <iant@google.com> - - * go-gcc.cc: Include "toplev.h". - (Gcc_backend::immutable_struct): New function. - (Gcc_backend::immutable_struct_set_init): New function. - (Gcc_backend::immutable_struct_reference): New function. - * Make-lang.in (go/go-gcc.o): Depend on toplev.h. - -2011-06-09 Ian Lance Taylor <iant@google.com> - - * go-gcc.cc (Gcc_backend::zero_expression): New function. - -2011-06-07 Richard Guenther <rguenther@suse.de> - - * go-lang.c (go_langhook_init): Do not set - size_type_node or call set_sizetype. - -2011-05-27 Ian Lance Taylor <iant@google.com> - - * go-backend.c: Include "output.h". - (go_write_export_data): New function. - * go-c.h (go_write_export_data): Declare. - * Make-lang.in (go/go-backend.o): Depend on output.h. - (go/export.o): Depend on $(GO_C_H). Do not depend on - $(MACHMODE_H), output.h, or $(TARGET_H). - -2011-05-24 Joseph Myers <joseph@codesourcery.com> - - * Make-lang.in (GCCGO_OBJS): Remove prefix.o. - (gccgo$(exeext)): Use libcommon-target.a. - -2011-05-20 Joseph Myers <joseph@codesourcery.com> - - * Make-lang.in (GCCGO_OBJS): Remove intl.o and version.o. - -2011-05-13 Ian Lance Taylor <iant@google.com> - - * go-gcc.cc (Gcc_backend::function_type): When building a struct - for multiple results, check that all fields types have a size. - (Gcc_backend::placeholder_pointer_type): Permit name to be empty. - -2011-05-12 Ian Lance Taylor <iant@google.com> - - * go-gcc.cc (Gcc_backend::local_variable): Add is_address_taken - parameter. - (Gcc_backend::parameter_variable): Likewise. - -2011-05-07 Eric Botcazou <ebotcazou@adacore.com> - - * go-lang.c (global_bindings_p): Return bool and simplify. - -2011-05-05 Nathan Froyd <froydnj@codesourcery.com> - - * go-gcc.cc (Gcc_backend::switch_statement): Call build_case_label. - -2011-05-04 Ian Lance Taylor <iant@google.com> - - * go-gcc.cc (Gcc_backend::struct_type): Call fill_in_struct. - (Gcc_backend::fill_in_struct): New function. - (Gcc_backend::array_type): Implement. - (Gcc_backend::fill_in_array): New function. - (Gcc_backend::placeholder_pointer_type): New function. - (Gcc_backend::set_placeholder_pointer_type): New function. - (Gcc_backend::set_placeholder_function_type): New function. - (Gcc_backend::placeholder_struct_type): New function. - (Gcc_backend::set_placeholder_struct_type): New function. - (Gcc_backend::placeholder_array_type): New function. - (Gcc_backend::set_placeholder_array_type): New function. - (Gcc_backend::named_type): New function. - (Gcc_backend::circular_pointer_type): New function. - (Gcc_backend::is_circular_pointer_type): New function. - -2011-04-26 Ian Lance Taylor <iant@google.com> - - * go-gcc.cc (Gcc_backend::struct_type): Implement. - -2011-04-25 Ian Lance Taylor <iant@google.com> - - * go-gcc.cc (Gcc_backend::error_type): Implement. - (Gcc_backend::string_type): Remove. - (Gcc_backend::function_type): Change signature and implement. - (Gcc_backend::struct_type): Change signature. - (Gcc_backend::slice_type, Gcc_backend::map_type): Remove. - (Gcc_backend::channel_type, Gcc_backend::interface_type): Remove. - (Gcc_backend::pointer_type): Check for error. - * Make-lang.in (go/types.o): Depend on go/gofrontend/backend.h. - -2011-04-25 Evan Shaw <edsrzf@gmail.com> - - * go-gcc.c (class Gcc_tree): Make get_tree const. - (Gcc_backend::void_type): Implement. - (Gcc_backend::bool_type): Implement. - (Gcc_backend::integer_type): Implement. - (Gcc_backend::float_type): Implement. - (Gcc_backend::complex_type): New function. - (Gcc_backend::pointer_type): New function. - (Gcc_backend::make_type): New function. - (type_to_tree): New function. - -2011-04-21 Ian Lance Taylor <iant@google.com> - - * go-system.h (go_assert, go_unreachable): Define. - -2011-04-19 Ian Lance Taylor <iant@google.com> - - * go-system.h: Include "intl.h". - * Make-lang.in (GO_SYSTEM_H): Add intl.h. - (go/statements.o): Remove dependencies on intl.h $(TREE_H) - $(GIMPLE_H) convert.h tree-iterator.h $(TREE_FLOW_H) $(REAL_H). - -2011-04-19 Ian Lance Taylor <iant@google.com> - - * go-gcc.cc (Gcc_backend::temporary_variable): New function. - -2011-04-19 Ian Lance Taylor <iant@google.com> - - * go-gcc.cc (class Bblock): Define. - (Gcc_backend::if_statement): Change then_block and else_block to - Bblock*. - (Gcc_backend::block): New function. - (Gcc_backend::block_add_statements): New function. - (Gcc_backend::block_statement): New function. - (tree_to_block, block_to_tree): New functions. - -2011-04-18 Ian Lance Taylor <iant@google.com> - - * go-gcc.cc: Include "go-c.h". - (class Bvariable): Define. - (Gcc_backend::init_statement): New function. - (Gcc_backend::global_variable): New function. - (Gcc_backend::global_variable_set_init): New function. - (Gcc_backend::local_variable): New function. - (Gcc_backend::parameter_variable): New function. - (tree_to_type, var_to_tree): New functions. - * Make-lang.in (go/go-gcc.o): Depend on $(GO_C_H). - * (go/gogo-tree.o): Depend on go/gofrontend/backend.h. - -2011-04-15 Ian Lance Taylor <iant@google.com> - - * go-gcc.cc (Gcc_backend::compound_statement): New function. - (Gcc_backend::assignment_statement): Use error_statement. - (Gcc_backend::return_statement): Likewise. - (Gcc_backend::if_statement): Likewise. - (Gcc_backend::switch_statement): Likewise. - (Gcc_backend::statement_list): Likewise. - -2011-04-14 Ian Lance Taylor <iant@google.com> - - * go-gcc.cc (Backend::error_statement): New function. - -2011-04-13 Ian Lance Taylor <iant@google.com> - - * Make-lang.in (go/gogo-tree.o): depend on $(GO_RUNTIME_H). - -2011-04-13 Ian Lance Taylor <iant@google.com> - - * Make-lang.in (GO_OBJS): Add go/runtime.o. - (GO_RUNTIME_H): New variable. - (go/runtime.o): New target. - (go/gogo.o): Depend on $(GO_RUNTIME_H). - (go/statements.o): Likewise. - -2011-04-12 Nathan Froyd <froydnj@codesourcery.com> - - * go-lang.c (union lang_tree_node): Check for TS_COMMON before - calling TREE_CHAIN. - -2011-04-06 Ian Lance Taylor <iant@google.com> - - * go-gcc.cc (if_statement): Use build3_loc. - (Gcc_backend::switch_statement): New function. - (Gcc_backend::statement_list): New function. - -2011-04-06 Ian Lance Taylor <iant@google.com> - - * go-gcc.cc (Gcc_backend::if_statement): New function. - (tree_to_stat): New function. - (expr_to_tree): Renamed from expression_to_tree. - (stat_to_tree): Renamed from statement_to_tree. - -2011-04-06 Ian Lance Taylor <iant@google.com> - - * go-gcc.cc (Gcc_backend::expression_statement): New function. - -2011-04-04 Ian Lance Taylor <iant@google.com> - - * go-gcc.c (class Blabel): Define. - (Gcc_backend::make_expression): New function. - (get_identifier_from_string): New function. - (Gcc_backend::label): New function. - (Gcc_backend::label_definition_statement): New function. - (Gcc_backend::goto_statement): New function. - (Gcc_backend::label_address): New function. - (expression_to_tree): New function. - * Make-lang.in (go/expressions.o): Depend on - go/gofrontend/backend.h. - (go/gogo.o): Likewise. - -2011-04-04 Ian Lance Taylor <iant@google.com> - - * go-gcc.cc: #include "tree-iterator.h", "gimple.h", and "gogo.h". - (class Bfunction): Define. - (Gcc_backend::assignment_statement): Rename from assignment. - Check for errors. - (Gcc_backend::return_statement): New function. - (tree_to_function): New function. - * Make-lang.in (go/go-gcc.o): Depend on tree-iterator.h, - $(GIMPLE_H), and $(GO_GOGO_H). - -2011-04-03 Ian Lance Taylor <iant@google.com> - - * go-gcc.cc: New file. - * Make-lang.in (GO_OBJS): Add go/go-gcc.o. - (go/go-gcc.o): New target. - (go/go.o): Depend on go/gofrontend/backend.h. - (go/statements.o): Likewise. - -2011-02-14 Ralf Wildenhues <Ralf.Wildenhues@gmx.de> - - * gccgo.texi (Top, Import and Export): Fix a typo and a markup nit. - -2011-02-08 Ian Lance Taylor <iant@google.com> - - * go-lang.c (go_langhook_init_options_struct): Set - frontend_set_flag_errno_math. Don't set x_flag_trapping_math. - -2011-01-31 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> - - * gospec.c (lang_specific_driver) [HAVE_LD_STATIC_DYNAMIC] Use - LD_STATIC_OPTION, LD_DYNAMIC_OPTION. - -2011-01-21 Ian Lance Taylor <iant@google.com> - - * go-lang.c (go_langhook_init): Omit float_type_size when calling - go_create_gogo. - * go-c.h: Update declaration of go_create_gogo. - -2011-01-13 Ian Lance Taylor <iant@google.com> - - * go-backend.c: Include "rtl.h" and "target.h". - (go_imported_unsafe): New function. - * go-c.h (go_imported_unsafe): Declare. - * Make-lang.in (go/go-backend.o): Depend on $(RTL_H). - (go/gogo-tree.o): Remove dependency on $(RTL_H). - (go/unsafe.o): Depend on $(GO_C_H). - -2010-12-31 Joern Rennecke <amylaar@spamcop.net> - - PR go/47113 - * go-backend.c: (go_field_alignment): Add ATTRIBUTE_UNUSED to - variable ‘field’ . - -2010-12-21 Ian Lance Taylor <iant@google.com> - - * Make-lang.in (check-go): Remove. - (lang_checks_parallelized): Add check-go. - (check_go_parallelize): Set. - -2010-12-13 Ian Lance Taylor <iant@google.com> - - * gospec.c (lang_specific_driver): Add a -o option if not linking - and there is no -o option already. - -2010-12-07 Ian Lance Taylor <iant@google.com> - - PR tree-optimization/46805 - PR tree-optimization/46833 - * go-lang.c (go_langhook_type_for_mode): Handle vector modes. - -2010-12-06 Ian Lance Taylor <iant@google.com> - - PR other/46789 - PR bootstrap/46812 - * go-lang.c (go_char_p): Define type and vectors. - (go_search_dirs): New static variable. - (go_langhook_handle_option): Use version and version/machine - directories for -L. - (go_langhook_post_options): Add non-specific -L paths. - * Make-lang.in (go/go-lang.o): Define DEFAULT_TARGET_VERSION and - DEFAULT_TARGET_MACHINE when compiling. - * gccgo.texi (Invoking gccgo): Only document -L for linking. - (Import and Export): Don't mention -L for finding import files. - -2010-12-03 Ian Lance Taylor <iant@google.com> - - PR bootstrap/46776 - * go-backend.c: New file. - * go-c.h (go_type_alignment): Declare. - (go_field_alignment, go_trampoline_info): Declare. - * Make-lang.in (GO_OBJS): Add go/go-backend.o. - (go/go-backend.o): New target. - (go/go-lang.o): Make dependencies match source file. - (go/expressions.o): Don't depend on $(TM_H) $(TM_P_H). - (go/gogo-tree.o): Don't depend on $(TM_H). - -2010-12-03 Ian Lance Taylor <iant@google.com> - - * config-lang.in (build_by_default): Set to no. - -2010-12-02 Ian Lance Taylor <iant@google.com> - - Go frontend added to gcc repository. diff --git a/gcc-4.8.1/gcc/go/Make-lang.in b/gcc-4.8.1/gcc/go/Make-lang.in deleted file mode 100644 index dd9808092..000000000 --- a/gcc-4.8.1/gcc/go/Make-lang.in +++ /dev/null @@ -1,318 +0,0 @@ -# Make-lang.in -- Top level -*- makefile -*- fragment for gcc Go frontend. - -# Copyright (C) 2009-2013 Free Software Foundation, Inc. - -# This file is part of GCC. - -# GCC 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, or (at your option) -# any later version. - -# GCC 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 GCC; see the file COPYING3. If not see -# <http://www.gnu.org/licenses/>. - -# This file provides the language dependent support in the main Makefile. - -# Installation name. - -GCCGO_INSTALL_NAME := $(shell echo gccgo|sed '$(program_transform_name)') -GCCGO_TARGET_INSTALL_NAME := $(target_noncanonical)-$(shell echo gccgo|sed '$(program_transform_name)') - -# The name for selecting go in LANGUAGES. -go: go1$(exeext) - -.PHONY: go - -gospec.o: $(srcdir)/go/gospec.c $(SYSTEM_H) coretypes.h $(TM_H) $(GCC_H) \ - $(CONFIG_H) opts.h - (SHLIB='$(SHLIB)'; \ - $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(DRIVER_DEFINES) \ - $(INCLUDES) $(srcdir)/go/gospec.c) - -GCCGO_OBJS = $(GCC_OBJS) gospec.o -gccgo$(exeext): $(GCCGO_OBJS) $(EXTRA_GCC_OBJS) libcommon-target.a $(LIBDEPS) - +$(LINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ \ - $(GCCGO_OBJS) $(EXTRA_GCC_OBJS) libcommon-target.a \ - $(EXTRA_GCC_LIBS) $(LIBS) - -# The cross-compiler version. This is built mainly as a signal to the -# go.install-common target. If this executable exists, it means that -# go.all.cross was run. -gccgo-cross$(exeext): gccgo$(exeext) - -rm -f gccgo-cross$(exeext) - cp gccgo$(exeext) gccgo-cross$(exeext) - -# Use strict warnings. -go-warn = $(STRICT_WARN) - -GO_OBJS = \ - go/ast-dump.o \ - go/dataflow.o \ - go/export.o \ - go/expressions.o \ - go/go-backend.o \ - go/go-dump.o \ - go/go-gcc.o \ - go/go-lang.o \ - go/go-linemap.o \ - go/go-optimize.o \ - go/go.o \ - go/gogo-tree.o \ - go/gogo.o \ - go/import.o \ - go/import-archive.o \ - go/lex.o \ - go/parse.o \ - go/runtime.o \ - go/statements.o \ - go/types.o \ - go/unsafe.o - -go1$(exeext): $(GO_OBJS) attribs.o $(BACKEND) $(LIBDEPS) - +$(CXX) $(ALL_CXXFLAGS) $(LDFLAGS) -o $@ \ - $(GO_OBJS) attribs.o $(BACKEND) $(LIBS) $(BACKENDLIBS) - -# Documentation. - -GO_TEXI_FILES = \ - go/gccgo.texi \ - $(gcc_docdir)/include/fdl.texi \ - $(gcc_docdir)/include/gpl_v3.texi \ - $(gcc_docdir)/include/gcc-common.texi \ - gcc-vers.texi - -doc/gccgo.info: $(GO_TEXI_FILES) - if test "x$(BUILD_INFO)" = xinfo; then \ - rm -f doc/gccgo.info*; \ - $(MAKEINFO) $(MAKEINFOFLAGS) -I $(gcc_docdir) \ - -I $(gcc_docdir)/include -o $@ $<; \ - else true; fi - -doc/gccgo.dvi: $(GO_TEXI_FILES) - $(TEXI2DVI) -I $(abs_docdir) -I $(abs_docdir)/include -o $@ $< - -doc/gccgo.pdf: $(GO_TEXI_FILES) - $(TEXI2PDF) -I $(abs_docdir) -I $(abs_docdir)/include -o $@ $< - -$(build_htmldir)/go/index.html: $(GO_TEXI_FILES) - $(mkinstalldirs) $(@D) - rm -f $(@D)/* - $(TEXI2HTML) -I $(gcc_docdir) -I $(gcc_docdir)/include \ - -I $(srcdir)/go -o $(@D) $< - -.INTERMEDIATE: gccgo.pod - -gccgo.pod: go/gccgo.texi - -$(TEXI2POD) -D gccgo < $< > $@ - -# Build hooks. - -go.all.cross: gccgo-cross$(exeext) -go.start.encap: gccgo$(exeext) -go.rest.encap: -go.info: doc/gccgo.info -go.dvi: doc/gccgo.dvi -go.pdf: doc/gccgo.pdf -go.html: $(build_htmldir)/go/index.html -go.srcinfo: doc/gccgo.info - -cp -p $^ $(srcdir)/doc -go.srcextra: -go.tags: force - cd $(srcdir)/go; \ - etags -o TAGS.sub *.c *.h gofrontend/*.h gofrontend/*.cc; \ - etags --include TAGS.sub --include ../TAGS.sub -go.man: doc/gccgo.1 -go.srcman: doc/gccgo.1 - -cp -p $^ $(srcdir)/doc - -lang_checks += check-go -lang_checks_parallelized += check-go -check_go_parallelize = go-test.exp=*/test/\[0-57-9a-bd-hj-zA-Z\]* \ - go-test.exp=*/test/c* \ - go-test.exp=*/test/i* \ - go-test.exp=*/test/6* - -# Install hooks. - -go.install-common: installdirs - -rm -f $(DESTDIR)$(bindir)/$(GCCGO_INSTALL_NAME)$(exeext) - $(INSTALL_PROGRAM) gccgo$(exeext) $(DESTDIR)$(bindir)/$(GCCGO_INSTALL_NAME)$(exeext) - -if test -f go1$(exeext); then \ - if test -f gccgo-cross$(exeext); then \ - :; \ - else \ - rm -f $(DESTDIR)$(bindir)/$(GCCGO_TARGET_INSTALL_NAME)$(exeext); \ - ( cd $(DESTDIR)$(bindir) && \ - $(LN) $(GCCGO_INSTALL_NAME)$(exeext) $(GCCGO_TARGET_INSTALL_NAME)$(exeext) ); \ - fi; \ - fi - -go.install-plugin: - -go.install-info: $(DESTDIR)$(infodir)/gccgo.info - -go.install-pdf: doc/gccgo.pdf - @$(NORMAL_INSTALL) - test -z "$(pdfdir)" || $(mkinstalldirs) "$(DESTDIR)$(pdfdir)/gcc" - @for p in doc/gccgo.pdf; do \ - if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ - f=$(pdf__strip_dir) \ - echo " $(INSTALL_DATA) '$$d$$p' '$(DESTDIR)$(pdfdir)/gcc/$$f'"; \ - $(INSTALL_DATA) "$$d$$p" "$(DESTDIR)$(pdfdir)/gcc/$$f"; \ - done - -go.install-html: $(build_htmldir)/go - @$(NORMAL_INSTALL) - test -z "$(htmldir)" || $(mkinstalldirs) "$(DESTDIR)$(htmldir)" - @for p in $(build_htmldir)/go; do \ - if test -f "$$p" || test -d "$$p"; then d=""; else d="$(srcdir)/"; fi; \ - f=$(html__strip_dir) \ - if test -d "$$d$$p"; then \ - echo " $(mkinstalldirs) '$(DESTDIR)$(htmldir)/$$f'"; \ - $(mkinstalldirs) "$(DESTDIR)$(htmldir)/$$f" || exit 1; \ - echo " $(INSTALL_DATA) '$$d$$p'/* '$(DESTDIR)$(htmldir)/$$f'"; \ - $(INSTALL_DATA) "$$d$$p"/* "$(DESTDIR)$(htmldir)/$$f"; \ - else \ - echo " $(INSTALL_DATA) '$$d$$p' '$(DESTDIR)$(htmldir)/$$f'"; \ - $(INSTALL_DATA) "$$d$$p" "$(DESTDIR)$(htmldir)/$$f"; \ - fi; \ - done - -go.install-man: $(DESTDIR)$(man1dir)/$(GCCGO_INSTALL_NAME)$(man1ext) - -$(DESTDIR)$(man1dir)/$(GCCGO_INSTALL_NAME)$(man1ext): doc/gccgo.1 installdirs - -rm -f $@ - -$(INSTALL_DATA) $< $@ - -chmod a-x $@ - -go.uninstall: - rm -rf $(DESTDIR)$(bindir)/$(GCCGO_INSTALL_NAME)$(exeext) - rm -rf $(DESTDIR)$(man1dir)/$(GCCGO_INSTALL_NAME)$(man1ext) - rm -rf $(DESTDIR)$(bindir)/$(GCCGO_TARGET_INSTALL_NAME)$(exeext) - rm -rf $(DESTDIR)$(infodir)/gccgo.info* - -# Clean hooks. - -go.mostlyclean: - -rm -f go/*$(objext) - -rm -f go/*$(coverageexts) -go.clean: -go.distclean: -go.maintainer-clean: - -rm -f $(docobjdir)/gccgo.1 - -# Stage hooks. - -go.stage1: stage1-start - -mv go/*$(objext) stage1/go -go.stage2: stage2-start - -mv go/*$(objext) stage2/go -go.stage3: stage3-start - -mv go/*$(objext) stage3/go -go.stage4: stage4-start - -mv go/*$(objext) stage4/go -go.stageprofile: stageprofile-start - -mv go/*$(objext) stageprofile/go -go.stagefeedback: stagefeedback-start - -mv go/*$(objext) stagefeedback/go - -GO_SYSTEM_H = go/go-system.h $(CONFIG_H) $(SYSTEM_H) coretypes.h \ - $(DIAGNOSTIC_CORE_H) $(INPUT_H) intl.h - -GO_C_H = go/go-c.h $(MACHMODE_H) -GO_LINEMAP_H = go/gofrontend/go-linemap.h $(GO_SYSTEM_H) go/go-location.h -GO_LEX_H = go/gofrontend/lex.h go/gofrontend/operator.h $(GO_LINEMAP_H) -GO_PARSE_H = go/gofrontend/parse.h -GO_GOGO_H = go/gofrontend/gogo.h $(GO_LINEMAP_H) -GO_TYPES_H = go/gofrontend/types.h $(GO_LINEMAP_H) -GO_STATEMENTS_H = go/gofrontend/statements.h go/gofrontend/operator.h -GO_EXPRESSIONS_H = go/gofrontend/expressions.h go/gofrontend/operator.h -GO_EXPORT_H = go/gofrontend/export.h go/gofrontend/string-dump.h -GO_IMPORT_H = go/gofrontend/import.h $(GO_EXPORT_H) $(GO_LINEMAP_H) -GO_RUNTIME_H = go/gofrontend/runtime.h go/gofrontend/runtime.def -GO_AST_DUMP_H = go/gofrontend/ast-dump.h go/gofrontend/string-dump.h - -go/go-backend.o: go/go-backend.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ - $(TM_H) $(RTL_H) $(TREE_H) $(TM_P_H) output.h $(TARGET_H) \ - $(COMMON_TARGET_H) - -CFLAGS-go/go-lang.o += -DDEFAULT_TARGET_VERSION=\"$(version)\" \ - -DDEFAULT_TARGET_MACHINE=\"$(target_noncanonical)\" -go/go-lang.o: go/go-lang.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(OPTS_H) \ - $(TREE_H) $(GIMPLE_H) $(GGC_H) $(TOPLEV_H) debug.h options.h \ - $(FLAGS_H) convert.h $(DIAGNOSTIC_H) langhooks.h \ - $(LANGHOOKS_DEF_H) $(EXCEPT_H) $(TARGET_H) $(GO_C_H) \ - gt-go-go-lang.h gtype-go.h $(COMMON_TARGET_H) - -GOINCLUDES = -I $(srcdir)/go -I $(srcdir)/go/gofrontend - -go/go-gcc.o: go/go-gcc.cc $(GO_SYSTEM_H) $(TREE_H) tree-iterator.h \ - $(GIMPLE_H) toplev.h output.h $(GO_C_H) $(GO_GOGO_H) \ - go/gofrontend/backend.h - $(CXX) -c $(GOINCLUDES) $(ALL_CPPFLAGS) $(ALL_CXXFLAGS) $< $(OUTPUT_OPTION) - -go/go-linemap.o: go/go-linemap.cc $(GO_SYSTEM_H) $(GO_LINEMAP_H) - $(CXX) -c $(GOINCLUDES) $(ALL_CPPFLAGS) $(ALL_CXXFLAGS) $< $(OUTPUT_OPTION) - -go/%.o: go/gofrontend/%.cc - $(CXX) -c $(GOINCLUDES) $(ALL_CPPFLAGS) $(ALL_CXXFLAGS) $< $(OUTPUT_OPTION) - -go/ast-dump.o: go/gofrontend/ast-dump.cc $(GO_SYSTME_H) $(GO_GOGO_H) \ - $(GO_EXPRESSIONS_H) $(GO_STATEMENTS_H) $(GO_TYPES_H) \ - $(GO_AST_DUMP_H) $(GO_C_H) go/gofrontend/go-dump.h -go/dataflow.o: go/gofrontend/dataflow.cc $(GO_SYSTEM_H) $(GO_GOGO_H) \ - $(GO_EXPRESSIONS_H) $(GO_STATEMENTS_H) go/gofrontend/dataflow.h -go/export.o: go/gofrontend/export.cc $(GO_SYSTEM_H) \ - $(srcdir)/../include/sha1.h $(GO_C_H) $(GO_GOGO_H) $(GO_TYPES_H) \ - $(GO_STATEMENTS_H) $(GO_EXPORT_H) -go/expressions.o: go/gofrontend/expressions.cc $(GO_SYSTEM_H) $(TOPLEV_H) \ - intl.h $(TREE_H) $(GIMPLE_H) tree-iterator.h convert.h $(REAL_H) \ - realmpfr.h $(GO_C_H) $(GO_GOGO_H) $(GO_TYPES_H) \ - $(GO_EXPORT_H) $(GO_IMPORT_H) $(GO_STATEMENTS_H) $(GO_LEX_H) \ - $(GO_RUNTIME_H) go/gofrontend/backend.h $(GO_EXPRESSIONS_H) \ - $(GO_AST_DUMP_H) -go/go.o: go/gofrontend/go.cc $(GO_SYSTEM_H) $(GO_C_H) $(GO_LEX_H) \ - $(GO_PARSE_H) go/gofrontend/backend.h $(GO_GOGO_H) -go/go-dump.o: go/gofrontend/go-dump.cc $(GO_SYSTEM_H) $(GO_C_H) \ - go/gofrontend/go-dump.h -go/go-optimize.o: go/gofrontend/go-optimize.cc $(GO_SYSTEM_H) $(GO_C_H) \ - go/gofrontend/go-optimize.h -go/gogo-tree.o: go/gofrontend/gogo-tree.cc $(GO_SYSTEM_H) $(TOPLEV_H) \ - $(TREE_H) $(GIMPLE_H) tree-iterator.h $(CGRAPH_H) langhooks.h \ - convert.h output.h $(DIAGNOSTIC_H) $(GO_TYPES_H) \ - $(GO_EXPRESSIONS_H) $(GO_STATEMENTS_H) $(GO_RUNTIME_H) \ - go/gofrontend/backend.h $(GO_GOGO_H) -go/gogo.o: go/gofrontend/gogo.cc $(GO_SYSTEM_H) \ - $(srcdir)/../include/filenames.h $(GO_C_H) go/gofrontend/go-dump.h \ - $(GO_LEX_H) $(GO_TYPES_H) $(GO_STATEMENTS_H) $(GO_EXPRESSIONS_H) \ - go/gofrontend/dataflow.h $(GO_RUNTIME_H) $(GO_IMPORT_H) \ - $(GO_EXPORT_H) go/gofrontend/backend.h $(GO_GOGO_H) -go/import.o: go/gofrontend/import.cc $(GO_SYSTEM_H) \ - $(srcdir)/../include/filenames.h $(srcdir)/../include/simple-object.h \ - $(GO_C_H) $(GO_GOGO_H) $(GO_LEX_H) $(GO_TYPES_H) $(GO_EXPORT_H) \ - $(GO_IMPORT_H) -go/import-archive.o: go/gofrontend/import-archive.cc $(GO_SYSTEM_H) \ - $(GO_IMPORT_H) -go/lex.o: go/gofrontend/lex.cc $(GO_LEX_H) $(GO_SYSTEM_H) -go/parse.o: go/gofrontend/parse.cc $(GO_SYSTEM_H) $(GO_LEX_H) $(GO_GOGO_H) \ - $(GO_TYPES_H) $(GO_STATEMENTS_H) $(GO_EXPRESSIONS_H) $(GO_PARSE_H) -go/runtime.o: go/gofrontend/runtime.cc $(GO_SYSTEM_H) $(GO_GOGO_H) \ - $(GO_TYPES_H) $(GO_EXPRESSIONS_H) $(GO_RUNTIME_H) \ - go/gofrontend/runtime.def -go/statements.o: go/gofrontend/statements.cc $(GO_SYSTEM_H) \ - $(GO_C_H) $(GO_TYPES_H) $(GO_EXPRESSIONS_H) $(GO_GOGO_H) \ - $(GO_RUNTIME_H) go/gofrontend/backend.h $(GO_STATEMENTS_H) \ - $(GO_AST_DUMP_H) -go/types.o: go/gofrontend/types.cc $(GO_SYSTEM_H) $(TOPLEV_H) intl.h $(TREE_H) \ - $(GIMPLE_H) $(REAL_H) convert.h $(GO_C_H) $(GO_GOGO_H) \ - go/gofrontend/operator.h $(GO_EXPRESSIONS_H) $(GO_STATEMENTS_H) \ - $(GO_EXPORT_H) $(GO_IMPORT_H) go/gofrontend/backend.h $(GO_TYPES_H) -go/unsafe.o: go/gofrontend/unsafe.cc $(GO_SYSTEM_H) $(GO_C_H) $(GO_TYPES_H) \ - $(GO_GOGO_H) diff --git a/gcc-4.8.1/gcc/go/README.gcc b/gcc-4.8.1/gcc/go/README.gcc deleted file mode 100644 index 3c764f7a9..000000000 --- a/gcc-4.8.1/gcc/go/README.gcc +++ /dev/null @@ -1,3 +0,0 @@ -The files in the gofrontend subdirectory are mirrored from the -gofrontend project hosted at http://code.google.com/p/gofrontend. -These files are the ones in the go subdirectory of that project. diff --git a/gcc-4.8.1/gcc/go/config-lang.in b/gcc-4.8.1/gcc/go/config-lang.in deleted file mode 100644 index fe9bb758f..000000000 --- a/gcc-4.8.1/gcc/go/config-lang.in +++ /dev/null @@ -1,40 +0,0 @@ -# config-lang.in -- Top level configure fragment for gcc Go frontend. - -# Copyright (C) 2009-2013 Free Software Foundation, Inc. - -# This file is part of GCC. - -# GCC 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, or (at your option) -# any later version. - -# GCC 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 GCC; see the file COPYING3. If not see -# <http://www.gnu.org/licenses/>. - -# Configure looks for the existence of this file to auto-config each language. -# We define several parameters used by configure: -# -# language - name of language as it would appear in $(LANGUAGES) -# compilers - value to add to $(COMPILERS) - -language="go" - -compilers="go1\$(exeext)" - -target_libs="target-libgo target-libffi target-libbacktrace" - -# The Go frontend is written in C++, so we need to build the C++ -# compiler during stage 1. -lang_requires_boot_languages=c++ - -gtfiles="\$(srcdir)/go/go-lang.c \$(srcdir)/go/go-c.h" - -# Do not build by default. -build_by_default="no" diff --git a/gcc-4.8.1/gcc/go/gccgo.texi b/gcc-4.8.1/gcc/go/gccgo.texi deleted file mode 100644 index f6fc3a6b5..000000000 --- a/gcc-4.8.1/gcc/go/gccgo.texi +++ /dev/null @@ -1,402 +0,0 @@ -\input texinfo @c -*-texinfo-*- -@setfilename gccgo.info -@settitle The GNU Go Compiler - -@c Merge the standard indexes into a single one. -@syncodeindex fn cp -@syncodeindex vr cp -@syncodeindex ky cp -@syncodeindex pg cp -@syncodeindex tp cp - -@include gcc-common.texi - -@c Copyright years for this manual. -@set copyrights-go 2010-2013 - -@copying -@c man begin COPYRIGHT -Copyright @copyright{} @value{copyrights-go} Free Software Foundation, Inc. - -Permission is granted to copy, distribute and/or modify this document -under the terms of the GNU Free Documentation License, Version 1.3 or -any later version published by the Free Software Foundation; with no -Invariant Sections, the Front-Cover Texts being (a) (see below), and -with the Back-Cover Texts being (b) (see below). -A copy of the license is included in the -@c man end -section entitled ``GNU Free Documentation License''. -@ignore -@c man begin COPYRIGHT -man page gfdl(7). -@c man end -@end ignore - -@c man begin COPYRIGHT - -(a) The FSF's Front-Cover Text is: - - A GNU Manual - -(b) The FSF's Back-Cover Text is: - - You have freedom to copy and modify this GNU Manual, like GNU - software. Copies published by the Free Software Foundation raise - funds for GNU development. -@c man end -@end copying - -@ifinfo -@format -@dircategory Software development -@direntry -* Gccgo: (gccgo). A GCC-based compiler for the Go language -@end direntry -@end format - -@insertcopying -@end ifinfo - -@titlepage -@title The GNU Go Compiler -@versionsubtitle -@author Ian Lance Taylor - -@page -@vskip 0pt plus 1filll -Published by the Free Software Foundation @* -51 Franklin Street, Fifth Floor@* -Boston, MA 02110-1301, USA@* -@sp 1 -@insertcopying -@end titlepage -@contents -@page - -@node Top -@top Introduction - -This manual describes how to use @command{gccgo}, the GNU compiler for -the Go programming language. This manual is specifically about -@command{gccgo}. For more information about the Go programming -language in general, including language specifications and standard -package documentation, see @uref{http://golang.org/}. - -@menu -* Copying:: The GNU General Public License. -* GNU Free Documentation License:: - How you can share and copy this manual. -* Invoking gccgo:: How to run gccgo. -* Import and Export:: Importing and exporting package data. -* C Interoperability:: Calling C from Go and vice-versa. -* Index:: Index. -@end menu - - -@include gpl_v3.texi - -@include fdl.texi - - -@node Invoking gccgo -@chapter Invoking gccgo - -@c man title gccgo A GCC-based compiler for the Go language - -@ignore -@c man begin SYNOPSIS gccgo -gccgo [@option{-c}|@option{-S}] - [@option{-g}] [@option{-pg}] [@option{-O}@var{level}] - [@option{-I}@var{dir}@dots{}] [@option{-L}@var{dir}@dots{}] - [@option{-o} @var{outfile}] @var{infile}@dots{} - -Only the most useful options are listed here; see below for the -remainder. -@c man end -@c man begin SEEALSO -gpl(7), gfdl(7), fsf-funding(7), gcc(1) -and the Info entries for @file{gccgo} and @file{gcc}. -@c man end -@end ignore - -@c man begin DESCRIPTION gccgo - -The @command{gccgo} command is a frontend to @command{gcc} and -supports many of the same options. @xref{Option Summary, , Option -Summary, gcc, Using the GNU Compiler Collection (GCC)}. This manual -only documents the options specific to @command{gccgo}. - -The @command{gccgo} command may be used to compile Go source code into -an object file, link a collection of object files together, or do both -in sequence. - -Go source code is compiled as packages. A package consists of one or -more Go source files. All the files in a single package must be -compiled together, by passing all the files as arguments to -@command{gccgo}. A single invocation of @command{gccgo} may only -compile a single package. - -One Go package may @code{import} a different Go package. The imported -package must have already been compiled; @command{gccgo} will read -the import data directly from the compiled package. When this package -is later linked, the compiled form of the package must be included in -the link command. - -@c man end - -@c man begin OPTIONS gccgo - -@table @gcctabopt -@item -I@var{dir} -@cindex @option{-I} -Specify a directory to use when searching for an import package at -compile time. - -@item -L@var{dir} -@cindex @option{-L} -When linking, specify a library search directory, as with -@command{gcc}. - -@item -fgo-pkgpath=@var{string} -@cindex @option{-fgo-pkgpath} -Set the package path to use. This sets the value returned by the -PkgPath method of reflect.Type objects. It is also used for the names -of globally visible symbols. The argument to this option should -normally be the string that will be used to import this package after -it has been installed; in other words, a pathname within the -directories specified by the @option{-I} option. - -@item -fgo-prefix=@var{string} -@cindex @option{-fgo-prefix} -An alternative to @option{-fgo-pkgpath}. The argument will be -combined with the package name from the source file to produce the -package path. If @option{-fgo-pkgpath} is used, @option{-fgo-prefix} -will be ignored. - -Go permits a single program to include more than one package with the -same name in the @code{package} clause in the source file, though -obviously the two packages must be imported using different pathnames. -In order for this to work with @command{gccgo}, either -@option{-fgo-pkgpath} or @option{-fgo-prefix} must be specified when -compiling a package. - -Using either @option{-fgo-pkgpath} or @option{-fgo-prefix} disables -the special treatment of the @code{main} package and permits that -package to be imported like any other. - -@item -fgo-relative-import-path=@var{dir} -@cindex @option{-fgo-relative-import-path} -A relative import is an import that starts with @file{./} or -@file{../}. If this option is used, @command{gccgo} will use -@var{dir} as a prefix for the relative import when searching for it. - -@item -frequire-return-statement -@itemx -fno-require-return-statement -@cindex @option{-frequire-return-statement} -@cindex @option{-fno-require-return-statement} -By default @command{gccgo} will warn about functions which have one or -more return parameters but lack an explicit @code{return} statement. -This warning may be disabled using -@option{-fno-require-return-statement}. - -@item -fgo-check-divide-zero -@cindex @option{-fgo-check-divide-zero} -@cindex @option{-fno-go-check-divide-zero} -Add explicit checks for division by zero. In Go a division (or -modulos) by zero causes a panic. On Unix systems this is detected in -the runtime by catching the @code{SIGFPE} signal. Some processors, -such as PowerPC, do not generate a SIGFPE on division by zero. Some -runtimes do not generate a signal that can be caught. On those -systems, this option may be used. Or the checks may be removed via -@option{-fno-go-check-divide-zero}. This option is currently on by -default, but in the future may be off by default on systems that do -not require it. - -@item -fgo-check-divide-overflow -@cindex @option{-fgo-check-divide-overflow} -@cindex @option{-fno-go-check-divide-overflow} -Add explicit checks for division overflow. For example, division -overflow occurs when computing @code{INT_MIN / -1}. In Go this should -be wrapped, to produce @code{INT_MIN}. Some processors, such as x86, -generate a trap on division overflow. On those systems, this option -may be used. Or the checks may be removed via -@option{-fno-go-check-divide-overflow}. This option is currently on -by default, but in the future may be off by default on systems that do -not require it. -@end table - -@c man end - -@node Import and Export -@chapter Import and Export - -When @command{gccgo} compiles a package which exports anything, the -export information will be stored directly in the object file. When a -package is imported, @command{gccgo} must be able to find the file. - -@cindex @file{.gox} -When Go code imports the package @file{@var{gopackage}}, @command{gccgo} -will look for the import data using the following filenames, using the -first one that it finds. - -@table @file -@item @var{gopackage}.gox -@item lib@var{gopackage}.so -@item lib@var{gopackage}.a -@item @var{gopackage}.o -@end table - -The compiler will search for these files in the directories named by -any @option{-I} options, in order in which the directories appear on -the command line. The compiler will then search several standard -system directories. Finally the compiler will search the current -directory (to search the current directory earlier, use @samp{-I.}). - -The compiler will extract the export information directly from the -compiled object file. The file @file{@var{gopackage}.gox} will -typically contain nothing but export data. This can be generated from -@file{@var{gopackage}.o} via - -@smallexample -objcopy -j .go_export @var{gopackage}.o @var{gopackage}.gox -@end smallexample - -For example, it may be desirable to extract the export information -from several different packages into their independent -@file{@var{gopackage}.gox} files, and then to combine the different -package object files together into a single shared library or archive. - -At link time you must explicitly tell @command{gccgo} which files to -link together into the executable, as is usual with @command{gcc}. -This is different from the behaviour of other Go compilers. - -@node C Interoperability -@chapter C Interoperability - -When using @command{gccgo} there is limited interoperability with C, -or with C++ code compiled using @code{extern "C"}. - -@menu -* C Type Interoperability:: How C and Go types match up. -* Function Names:: How Go functions are named. -@end menu - -@node C Type Interoperability -@section C Type Interoperability - -Basic types map directly: an @code{int} in Go is an @code{int} in C, -etc. Go @code{byte} is equivalent to C @code{unsigned char}. -Pointers in Go are pointers in C. A Go @code{struct} is the same as C -@code{struct} with the same field names and types. - -@cindex @code{string} in C -The Go @code{string} type is currently defined as a two-element -structure: - -@smallexample -struct __go_string @{ - const unsigned char *__data; - int __length; -@}; -@end smallexample - -You can't pass arrays between C and Go. However, a pointer to an -array in Go is equivalent to a C pointer to the equivalent of the -element type. For example, Go @code{*[10]int} is equivalent to C -@code{int*}, assuming that the C pointer does point to 10 elements. - -@cindex @code{slice} in C -A slice in Go is a structure. The current definition is: - -@smallexample -struct __go_slice @{ - void *__values; - int __count; - int __capacity; -@}; -@end smallexample - -The type of a Go function with no receiver is equivalent to a C -function whose parameter types are equivalent. When a Go function -returns more than one value, the C function returns a struct. For -example, these functions have equivalent types: - -@smallexample -func GoFunction(int) (int, float) -struct @{ int i; float f; @} CFunction(int) -@end smallexample - -A pointer to a Go function is equivalent to a pointer to a C function -when the functions have equivalent types. - -Go @code{interface}, @code{channel}, and @code{map} types have no -corresponding C type (@code{interface} is a two-element struct and -@code{channel} and @code{map} are pointers to structs in C, but the -structs are deliberately undocumented). C @code{enum} types -correspond to some integer type, but precisely which one is difficult -to predict in general; use a cast. C @code{union} types have no -corresponding Go type. C @code{struct} types containing bitfields -have no corresponding Go type. C++ @code{class} types have no -corresponding Go type. - -Memory allocation is completely different between C and Go, as Go uses -garbage collection. The exact guidelines in this area are -undetermined, but it is likely that it will be permitted to pass a -pointer to allocated memory from C to Go. The responsibility of -eventually freeing the pointer will remain with C side, and of course -if the C side frees the pointer while the Go side still has a copy the -program will fail. When passing a pointer from Go to C, the Go -function must retain a visible copy of it in some Go variable. -Otherwise the Go garbage collector may delete the pointer while the C -function is still using it. - -@node Function Names -@section Function Names - -@cindex @code{extern} -@cindex external names -Go code can call C functions directly using a Go extension implemented -in @command{gccgo}: a function declaration may be preceded by a -comment giving the external name. The comment must be at the -beginning of the line and must start with @code{//extern}. This must -be followed by a space and then the external name of the function. -The function declaration must be on the line immediately after the -comment. For example, here is how the C function @code{open} can be -declared in Go: - -@smallexample -//extern open -func c_open(name *byte, mode int, perm int) int -@end smallexample - -The C function naturally expects a nul terminated string, which in Go -is equivalent to a pointer to an array (not a slice!) of @code{byte} -with a terminating zero byte. So a sample call from Go would look -like (after importing the @code{os} package): - -@smallexample -var name = [4]byte@{'f', 'o', 'o', 0@}; -i := c_open(&name[0], os.O_RDONLY, 0); -@end smallexample - -Note that this serves as an example only. To open a file in Go please -use Go's @code{os.Open} function instead. - -The name of Go functions accessed from C is subject to change. At -present the name of a Go function that does not have a receiver is -@code{prefix.package.Functionname}. The prefix is set by the -@option{-fgo-prefix} option used when the package is compiled; if the -option is not used, the default is simply @code{go}. To call the -function from C you must set the name using the @command{gcc} -@code{__asm__} extension. - -@smallexample -extern int go_function(int) __asm__ ("myprefix.mypackage.Function"); -@end smallexample - -@node Index -@unnumbered Index - -@printindex cp - -@bye diff --git a/gcc-4.8.1/gcc/go/go-backend.c b/gcc-4.8.1/gcc/go/go-backend.c deleted file mode 100644 index ea47138a5..000000000 --- a/gcc-4.8.1/gcc/go/go-backend.c +++ /dev/null @@ -1,198 +0,0 @@ -/* go-backend.c -- Go frontend interface to gcc backend. - Copyright (C) 2010-2013 Free Software Foundation, Inc. - -This file is part of GCC. - -GCC 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, or (at your option) any later -version. - -GCC 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 GCC; see the file COPYING3. If not see -<http://www.gnu.org/licenses/>. */ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "simple-object.h" -#include "tm.h" -#include "rtl.h" -#include "tree.h" -#include "tm_p.h" -#include "intl.h" -#include "output.h" /* for assemble_string */ -#include "target.h" -#include "common/common-target.h" - -#include "go-c.h" - -/* The segment name we pass to simple_object_start_read to find Go - export data. */ - -#ifndef GO_EXPORT_SEGMENT_NAME -#define GO_EXPORT_SEGMENT_NAME "__GNU_GO" -#endif - -/* The section name we use when reading and writing export data. */ - -#ifndef GO_EXPORT_SECTION_NAME -#define GO_EXPORT_SECTION_NAME ".go_export" -#endif - -/* This file holds all the cases where the Go frontend needs - information from gcc's backend. */ - -/* Return the alignment in bytes of a struct field of type T. */ - -unsigned int -go_field_alignment (tree t) -{ - unsigned int v; - - v = TYPE_ALIGN (t); - -#ifdef BIGGEST_FIELD_ALIGNMENT - if (v > BIGGEST_FIELD_ALIGNMENT) - v = BIGGEST_FIELD_ALIGNMENT; -#endif - -#ifdef ADJUST_FIELD_ALIGN - { - tree field ATTRIBUTE_UNUSED; - field = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL, t); - v = ADJUST_FIELD_ALIGN (field, v); - } -#endif - - return v / BITS_PER_UNIT; -} - -/* Return the size and alignment of a trampoline. */ - -void -go_trampoline_info (unsigned int *size, unsigned int *alignment) -{ - *size = TRAMPOLINE_SIZE; - *alignment = TRAMPOLINE_ALIGNMENT; -} - -/* This is called by the Go frontend proper if the unsafe package was - imported. When that happens we can not do type-based alias - analysis. */ - -void -go_imported_unsafe (void) -{ - flag_strict_aliasing = false; - - /* This is a real hack. init_varasm_once has already grabbed an - alias set, which we don't want when we aren't doing strict - aliasing. We reinitialize to make it do it again. This should - be OK in practice since we haven't really done anything yet. */ - init_varasm_once (); - - /* Let the backend know that the options have changed. */ - targetm.override_options_after_change (); -} - -/* This is called by the Go frontend proper to add data to the - section containing Go export data. */ - -void -go_write_export_data (const char *bytes, unsigned int size) -{ - static section* sec; - - if (sec == NULL) - { - gcc_assert (targetm_common.have_named_sections); - sec = get_section (GO_EXPORT_SECTION_NAME, SECTION_DEBUG, NULL); - } - - switch_to_section (sec); - assemble_string (bytes, size); -} - -/* The go_read_export_data function is called by the Go frontend - proper to read Go export data from an object file. FD is a file - descriptor open for reading. OFFSET is the offset within the file - where the object file starts; this will be 0 except when reading an - archive. On success this returns NULL and sets *PBUF to a buffer - allocated using malloc, of size *PLEN, holding the export data. If - the data is not found, this returns NULL and sets *PBUF to NULL and - *PLEN to 0. If some error occurs, this returns an error message - and sets *PERR to an errno value or 0 if there is no relevant - errno. */ - -const char * -go_read_export_data (int fd, off_t offset, char **pbuf, size_t *plen, - int *perr) -{ - simple_object_read *sobj; - const char *errmsg; - off_t sec_offset; - off_t sec_length; - int found; - char *buf; - ssize_t c; - - *pbuf = NULL; - *plen = 0; - - sobj = simple_object_start_read (fd, offset, GO_EXPORT_SEGMENT_NAME, - &errmsg, perr); - if (sobj == NULL) - { - /* If we get an error here, just pretend that we didn't find any - export data. This is the right thing to do if the error is - that the file was not recognized as an object file. This - will ignore file I/O errors, but it's not too big a deal - because we will wind up giving some other error later. */ - return NULL; - } - - found = simple_object_find_section (sobj, GO_EXPORT_SECTION_NAME, - &sec_offset, &sec_length, - &errmsg, perr); - simple_object_release_read (sobj); - if (!found) - return errmsg; - - if (lseek (fd, offset + sec_offset, SEEK_SET) < 0) - { - *perr = errno; - return _("lseek failed while reading export data"); - } - - buf = XNEWVEC (char, sec_length); - if (buf == NULL) - { - *perr = errno; - return _("memory allocation failed while reading export data"); - } - - c = read (fd, buf, sec_length); - if (c < 0) - { - *perr = errno; - free (buf); - return _("read failed while reading export data"); - } - - if (c < sec_length) - { - free (buf); - return _("short read while reading export data"); - } - - *pbuf = buf; - *plen = sec_length; - - return NULL; -} diff --git a/gcc-4.8.1/gcc/go/go-c.h b/gcc-4.8.1/gcc/go/go-c.h deleted file mode 100644 index 5871d9003..000000000 --- a/gcc-4.8.1/gcc/go/go-c.h +++ /dev/null @@ -1,66 +0,0 @@ -/* go-c.h -- Header file for go frontend gcc C interface. - Copyright (C) 2009-2013 Free Software Foundation, Inc. - -This file is part of GCC. - -GCC 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, or (at your option) any later -version. - -GCC 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 GCC; see the file COPYING3. If not see -<http://www.gnu.org/licenses/>. */ - -#ifndef GO_GO_C_H -#define GO_GO_C_H - -#define GO_EXTERN_C - -#include "machmode.h" - -/* Functions defined in the Go frontend proper called by the GCC - interface. */ - -extern int go_enable_dump (const char*); -extern int go_enable_optimize (const char*); - -extern void go_add_search_path (const char*); - -extern void go_create_gogo (int int_type_size, int pointer_size, - const char* pkgpath, const char *prefix, - const char *relative_import_path); - -extern void go_parse_input_files (const char**, unsigned int, - bool only_check_syntax, - bool require_return_statement); -extern void go_write_globals (void); - -extern tree go_type_for_size (unsigned int bits, int unsignedp); -extern tree go_type_for_mode (enum machine_mode, int unsignedp); - -/* Functions defined in the GCC interface called by the Go frontend - proper. */ - -extern void go_preserve_from_gc (tree); - -extern const char *go_localize_identifier (const char*); - -extern unsigned int go_field_alignment (tree); - -extern void go_trampoline_info (unsigned int *size, unsigned int *alignment); - -extern void go_imported_unsafe (void); - -extern void go_write_export_data (const char *, unsigned int); - -extern const char *go_read_export_data (int, off_t, char **, size_t *, int *); - -extern GTY(()) tree go_non_zero_struct; - -#endif /* !defined(GO_GO_C_H) */ diff --git a/gcc-4.8.1/gcc/go/go-gcc.cc b/gcc-4.8.1/gcc/go/go-gcc.cc deleted file mode 100644 index a6acf1374..000000000 --- a/gcc-4.8.1/gcc/go/go-gcc.cc +++ /dev/null @@ -1,1660 +0,0 @@ -// go-gcc.cc -- Go frontend to gcc IR. -// Copyright (C) 2011-2013 Free Software Foundation, Inc. -// Contributed by Ian Lance Taylor, Google. - -// This file is part of GCC. - -// GCC 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, or (at your option) any later -// version. - -// GCC 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 GCC; see the file COPYING3. If not see -// <http://www.gnu.org/licenses/>. - -#include "go-system.h" - -// This has to be included outside of extern "C", so we have to -// include it here before tree.h includes it later. -#include <gmp.h> - -#include "tree.h" -#include "tree-iterator.h" -#include "gimple.h" -#include "toplev.h" -#include "output.h" - -#include "go-c.h" - -#include "gogo.h" -#include "backend.h" - -// A class wrapping a tree. - -class Gcc_tree -{ - public: - Gcc_tree(tree t) - : t_(t) - { } - - tree - get_tree() const - { return this->t_; } - - void - set_tree(tree t) - { this->t_ = t; } - - private: - tree t_; -}; - -// In gcc, types, expressions, and statements are all trees. -class Btype : public Gcc_tree -{ - public: - Btype(tree t) - : Gcc_tree(t) - { } -}; - -class Bexpression : public Gcc_tree -{ - public: - Bexpression(tree t) - : Gcc_tree(t) - { } -}; - -class Bstatement : public Gcc_tree -{ - public: - Bstatement(tree t) - : Gcc_tree(t) - { } -}; - -class Bfunction : public Gcc_tree -{ - public: - Bfunction(tree t) - : Gcc_tree(t) - { } -}; - -class Bblock : public Gcc_tree -{ - public: - Bblock(tree t) - : Gcc_tree(t) - { } -}; - -class Bvariable : public Gcc_tree -{ - public: - Bvariable(tree t) - : Gcc_tree(t) - { } -}; - -class Blabel : public Gcc_tree -{ - public: - Blabel(tree t) - : Gcc_tree(t) - { } -}; - -// This file implements the interface between the Go frontend proper -// and the gcc IR. This implements specific instantiations of -// abstract classes defined by the Go frontend proper. The Go -// frontend proper class methods of these classes to generate the -// backend representation. - -class Gcc_backend : public Backend -{ - public: - // Types. - - Btype* - error_type() - { return this->make_type(error_mark_node); } - - Btype* - void_type() - { return this->make_type(void_type_node); } - - Btype* - bool_type() - { return this->make_type(boolean_type_node); } - - Btype* - integer_type(bool, int); - - Btype* - float_type(int); - - Btype* - complex_type(int); - - Btype* - pointer_type(Btype*); - - Btype* - function_type(const Btyped_identifier&, - const std::vector<Btyped_identifier>&, - const std::vector<Btyped_identifier>&, - const Location); - - Btype* - struct_type(const std::vector<Btyped_identifier>&); - - Btype* - array_type(Btype*, Bexpression*); - - Btype* - placeholder_pointer_type(const std::string&, Location, bool); - - bool - set_placeholder_pointer_type(Btype*, Btype*); - - bool - set_placeholder_function_type(Btype*, Btype*); - - Btype* - placeholder_struct_type(const std::string&, Location); - - bool - set_placeholder_struct_type(Btype* placeholder, - const std::vector<Btyped_identifier>&); - - Btype* - placeholder_array_type(const std::string&, Location); - - bool - set_placeholder_array_type(Btype*, Btype*, Bexpression*); - - Btype* - named_type(const std::string&, Btype*, Location); - - Btype* - circular_pointer_type(Btype*, bool); - - bool - is_circular_pointer_type(Btype*); - - size_t - type_size(Btype*); - - size_t - type_alignment(Btype*); - - size_t - type_field_alignment(Btype*); - - size_t - type_field_offset(Btype*, size_t index); - - // Expressions. - - Bexpression* - zero_expression(Btype*); - - // Statements. - - Bstatement* - error_statement() - { return this->make_statement(error_mark_node); } - - Bstatement* - expression_statement(Bexpression*); - - Bstatement* - init_statement(Bvariable* var, Bexpression* init); - - Bstatement* - assignment_statement(Bexpression* lhs, Bexpression* rhs, Location); - - Bstatement* - return_statement(Bfunction*, const std::vector<Bexpression*>&, - Location); - - Bstatement* - if_statement(Bexpression* condition, Bblock* then_block, Bblock* else_block, - Location); - - Bstatement* - switch_statement(Bexpression* value, - const std::vector<std::vector<Bexpression*> >& cases, - const std::vector<Bstatement*>& statements, - Location); - - Bstatement* - compound_statement(Bstatement*, Bstatement*); - - Bstatement* - statement_list(const std::vector<Bstatement*>&); - - // Blocks. - - Bblock* - block(Bfunction*, Bblock*, const std::vector<Bvariable*>&, - Location, Location); - - void - block_add_statements(Bblock*, const std::vector<Bstatement*>&); - - Bstatement* - block_statement(Bblock*); - - // Variables. - - Bvariable* - error_variable() - { return new Bvariable(error_mark_node); } - - Bvariable* - global_variable(const std::string& package_name, - const std::string& pkgpath, - const std::string& name, - Btype* btype, - bool is_external, - bool is_hidden, - bool in_unique_section, - Location location); - - void - global_variable_set_init(Bvariable*, Bexpression*); - - Bvariable* - local_variable(Bfunction*, const std::string&, Btype*, bool, - Location); - - Bvariable* - parameter_variable(Bfunction*, const std::string&, Btype*, bool, - Location); - - Bvariable* - temporary_variable(Bfunction*, Bblock*, Btype*, Bexpression*, bool, - Location, Bstatement**); - - Bvariable* - immutable_struct(const std::string&, bool, Btype*, Location); - - void - immutable_struct_set_init(Bvariable*, const std::string&, bool, Btype*, - Location, Bexpression*); - - Bvariable* - immutable_struct_reference(const std::string&, Btype*, Location); - - // Labels. - - Blabel* - label(Bfunction*, const std::string& name, Location); - - Bstatement* - label_definition_statement(Blabel*); - - Bstatement* - goto_statement(Blabel*, Location); - - Bexpression* - label_address(Blabel*, Location); - - private: - // Make a Bexpression from a tree. - Bexpression* - make_expression(tree t) - { return new Bexpression(t); } - - // Make a Bstatement from a tree. - Bstatement* - make_statement(tree t) - { return new Bstatement(t); } - - // Make a Btype from a tree. - Btype* - make_type(tree t) - { return new Btype(t); } - - Btype* - fill_in_struct(Btype*, const std::vector<Btyped_identifier>&); - - Btype* - fill_in_array(Btype*, Btype*, Bexpression*); - - tree - non_zero_size_type(tree); -}; - -// A helper function. - -static inline tree -get_identifier_from_string(const std::string& str) -{ - return get_identifier_with_length(str.data(), str.length()); -} - -// Get an unnamed integer type. - -Btype* -Gcc_backend::integer_type(bool is_unsigned, int bits) -{ - tree type; - if (is_unsigned) - { - if (bits == INT_TYPE_SIZE) - type = unsigned_type_node; - else if (bits == CHAR_TYPE_SIZE) - type = unsigned_char_type_node; - else if (bits == SHORT_TYPE_SIZE) - type = short_unsigned_type_node; - else if (bits == LONG_TYPE_SIZE) - type = long_unsigned_type_node; - else if (bits == LONG_LONG_TYPE_SIZE) - type = long_long_unsigned_type_node; - else - type = make_unsigned_type(bits); - } - else - { - if (bits == INT_TYPE_SIZE) - type = integer_type_node; - else if (bits == CHAR_TYPE_SIZE) - type = signed_char_type_node; - else if (bits == SHORT_TYPE_SIZE) - type = short_integer_type_node; - else if (bits == LONG_TYPE_SIZE) - type = long_integer_type_node; - else if (bits == LONG_LONG_TYPE_SIZE) - type = long_long_integer_type_node; - else - type = make_signed_type(bits); - } - return this->make_type(type); -} - -// Get an unnamed float type. - -Btype* -Gcc_backend::float_type(int bits) -{ - tree type; - if (bits == FLOAT_TYPE_SIZE) - type = float_type_node; - else if (bits == DOUBLE_TYPE_SIZE) - type = double_type_node; - else if (bits == LONG_DOUBLE_TYPE_SIZE) - type = long_double_type_node; - else - { - type = make_node(REAL_TYPE); - TYPE_PRECISION(type) = bits; - layout_type(type); - } - return this->make_type(type); -} - -// Get an unnamed complex type. - -Btype* -Gcc_backend::complex_type(int bits) -{ - tree type; - if (bits == FLOAT_TYPE_SIZE * 2) - type = complex_float_type_node; - else if (bits == DOUBLE_TYPE_SIZE * 2) - type = complex_double_type_node; - else if (bits == LONG_DOUBLE_TYPE_SIZE * 2) - type = complex_long_double_type_node; - else - { - type = make_node(REAL_TYPE); - TYPE_PRECISION(type) = bits / 2; - layout_type(type); - type = build_complex_type(type); - } - return this->make_type(type); -} - -// Get a pointer type. - -Btype* -Gcc_backend::pointer_type(Btype* to_type) -{ - tree to_type_tree = to_type->get_tree(); - if (to_type_tree == error_mark_node) - return this->error_type(); - tree type = build_pointer_type(to_type_tree); - return this->make_type(type); -} - -// Make a function type. - -Btype* -Gcc_backend::function_type(const Btyped_identifier& receiver, - const std::vector<Btyped_identifier>& parameters, - const std::vector<Btyped_identifier>& results, - Location location) -{ - tree args = NULL_TREE; - tree* pp = &args; - if (receiver.btype != NULL) - { - tree t = receiver.btype->get_tree(); - if (t == error_mark_node) - return this->error_type(); - *pp = tree_cons(NULL_TREE, t, NULL_TREE); - pp = &TREE_CHAIN(*pp); - } - - for (std::vector<Btyped_identifier>::const_iterator p = parameters.begin(); - p != parameters.end(); - ++p) - { - tree t = p->btype->get_tree(); - if (t == error_mark_node) - return this->error_type(); - *pp = tree_cons(NULL_TREE, t, NULL_TREE); - pp = &TREE_CHAIN(*pp); - } - - // Varargs is handled entirely at the Go level. When converted to - // GENERIC functions are not varargs. - *pp = void_list_node; - - tree result; - if (results.empty()) - result = void_type_node; - else if (results.size() == 1) - result = results.front().btype->get_tree(); - else - { - result = make_node(RECORD_TYPE); - tree field_trees = NULL_TREE; - pp = &field_trees; - for (std::vector<Btyped_identifier>::const_iterator p = results.begin(); - p != results.end(); - ++p) - { - const std::string name = (p->name.empty() - ? "UNNAMED" - : p->name); - tree name_tree = get_identifier_from_string(name); - tree field_type_tree = p->btype->get_tree(); - if (field_type_tree == error_mark_node) - return this->error_type(); - gcc_assert(TYPE_SIZE(field_type_tree) != NULL_TREE); - tree field = build_decl(location.gcc_location(), FIELD_DECL, - name_tree, field_type_tree); - DECL_CONTEXT(field) = result; - *pp = field; - pp = &DECL_CHAIN(field); - } - TYPE_FIELDS(result) = field_trees; - layout_type(result); - } - if (result == error_mark_node) - return this->error_type(); - - tree fntype = build_function_type(result, args); - if (fntype == error_mark_node) - return this->error_type(); - - return this->make_type(build_pointer_type(fntype)); -} - -// Make a struct type. - -Btype* -Gcc_backend::struct_type(const std::vector<Btyped_identifier>& fields) -{ - return this->fill_in_struct(this->make_type(make_node(RECORD_TYPE)), fields); -} - -// Fill in the fields of a struct type. - -Btype* -Gcc_backend::fill_in_struct(Btype* fill, - const std::vector<Btyped_identifier>& fields) -{ - tree fill_tree = fill->get_tree(); - tree field_trees = NULL_TREE; - tree* pp = &field_trees; - for (std::vector<Btyped_identifier>::const_iterator p = fields.begin(); - p != fields.end(); - ++p) - { - tree name_tree = get_identifier_from_string(p->name); - tree type_tree = p->btype->get_tree(); - if (type_tree == error_mark_node) - return this->error_type(); - tree field = build_decl(p->location.gcc_location(), FIELD_DECL, name_tree, - type_tree); - DECL_CONTEXT(field) = fill_tree; - *pp = field; - pp = &DECL_CHAIN(field); - } - TYPE_FIELDS(fill_tree) = field_trees; - layout_type(fill_tree); - return fill; -} - -// Make an array type. - -Btype* -Gcc_backend::array_type(Btype* element_btype, Bexpression* length) -{ - return this->fill_in_array(this->make_type(make_node(ARRAY_TYPE)), - element_btype, length); -} - -// Fill in an array type. - -Btype* -Gcc_backend::fill_in_array(Btype* fill, Btype* element_type, - Bexpression* length) -{ - tree element_type_tree = element_type->get_tree(); - tree length_tree = length->get_tree(); - if (element_type_tree == error_mark_node || length_tree == error_mark_node) - return this->error_type(); - - gcc_assert(TYPE_SIZE(element_type_tree) != NULL_TREE); - - length_tree = fold_convert(sizetype, length_tree); - - // build_index_type takes the maximum index, which is one less than - // the length. - tree index_type_tree = build_index_type(fold_build2(MINUS_EXPR, sizetype, - length_tree, - size_one_node)); - - tree fill_tree = fill->get_tree(); - TREE_TYPE(fill_tree) = element_type_tree; - TYPE_DOMAIN(fill_tree) = index_type_tree; - TYPE_ADDR_SPACE(fill_tree) = TYPE_ADDR_SPACE(element_type_tree); - layout_type(fill_tree); - - if (TYPE_STRUCTURAL_EQUALITY_P(element_type_tree)) - SET_TYPE_STRUCTURAL_EQUALITY(fill_tree); - else if (TYPE_CANONICAL(element_type_tree) != element_type_tree - || TYPE_CANONICAL(index_type_tree) != index_type_tree) - TYPE_CANONICAL(fill_tree) = - build_array_type(TYPE_CANONICAL(element_type_tree), - TYPE_CANONICAL(index_type_tree)); - - return fill; -} - -// Create a placeholder for a pointer type. - -Btype* -Gcc_backend::placeholder_pointer_type(const std::string& name, - Location location, bool) -{ - tree ret = build_distinct_type_copy(ptr_type_node); - if (!name.empty()) - { - tree decl = build_decl(location.gcc_location(), TYPE_DECL, - get_identifier_from_string(name), - ret); - TYPE_NAME(ret) = decl; - } - return this->make_type(ret); -} - -// Set the real target type for a placeholder pointer type. - -bool -Gcc_backend::set_placeholder_pointer_type(Btype* placeholder, - Btype* to_type) -{ - tree pt = placeholder->get_tree(); - if (pt == error_mark_node) - return false; - gcc_assert(TREE_CODE(pt) == POINTER_TYPE); - tree tt = to_type->get_tree(); - if (tt == error_mark_node) - { - placeholder->set_tree(error_mark_node); - return false; - } - gcc_assert(TREE_CODE(tt) == POINTER_TYPE); - TREE_TYPE(pt) = TREE_TYPE(tt); - if (TYPE_NAME(pt) != NULL_TREE) - { - // Build the data structure gcc wants to see for a typedef. - tree copy = build_variant_type_copy(pt); - TYPE_NAME(copy) = NULL_TREE; - DECL_ORIGINAL_TYPE(TYPE_NAME(pt)) = copy; - } - return true; -} - -// Set the real values for a placeholder function type. - -bool -Gcc_backend::set_placeholder_function_type(Btype* placeholder, Btype* ft) -{ - return this->set_placeholder_pointer_type(placeholder, ft); -} - -// Create a placeholder for a struct type. - -Btype* -Gcc_backend::placeholder_struct_type(const std::string& name, - Location location) -{ - tree ret = make_node(RECORD_TYPE); - if (!name.empty()) - { - tree decl = build_decl(location.gcc_location(), TYPE_DECL, - get_identifier_from_string(name), - ret); - TYPE_NAME(ret) = decl; - } - return this->make_type(ret); -} - -// Fill in the fields of a placeholder struct type. - -bool -Gcc_backend::set_placeholder_struct_type( - Btype* placeholder, - const std::vector<Btyped_identifier>& fields) -{ - tree t = placeholder->get_tree(); - gcc_assert(TREE_CODE(t) == RECORD_TYPE && TYPE_FIELDS(t) == NULL_TREE); - Btype* r = this->fill_in_struct(placeholder, fields); - - if (TYPE_NAME(t) != NULL_TREE) - { - // Build the data structure gcc wants to see for a typedef. - tree copy = build_distinct_type_copy(t); - TYPE_NAME(copy) = NULL_TREE; - DECL_ORIGINAL_TYPE(TYPE_NAME(t)) = copy; - } - - return r->get_tree() != error_mark_node; -} - -// Create a placeholder for an array type. - -Btype* -Gcc_backend::placeholder_array_type(const std::string& name, - Location location) -{ - tree ret = make_node(ARRAY_TYPE); - tree decl = build_decl(location.gcc_location(), TYPE_DECL, - get_identifier_from_string(name), - ret); - TYPE_NAME(ret) = decl; - return this->make_type(ret); -} - -// Fill in the fields of a placeholder array type. - -bool -Gcc_backend::set_placeholder_array_type(Btype* placeholder, - Btype* element_btype, - Bexpression* length) -{ - tree t = placeholder->get_tree(); - gcc_assert(TREE_CODE(t) == ARRAY_TYPE && TREE_TYPE(t) == NULL_TREE); - Btype* r = this->fill_in_array(placeholder, element_btype, length); - - // Build the data structure gcc wants to see for a typedef. - tree copy = build_distinct_type_copy(t); - TYPE_NAME(copy) = NULL_TREE; - DECL_ORIGINAL_TYPE(TYPE_NAME(t)) = copy; - - return r->get_tree() != error_mark_node; -} - -// Return a named version of a type. - -Btype* -Gcc_backend::named_type(const std::string& name, Btype* btype, - Location location) -{ - tree type = btype->get_tree(); - if (type == error_mark_node) - return this->error_type(); - - // The middle-end expects a basic type to have a name. In Go every - // basic type will have a name. The first time we see a basic type, - // give it whatever Go name we have at this point. - if (TYPE_NAME(type) == NULL_TREE - && location.gcc_location() == BUILTINS_LOCATION - && (TREE_CODE(type) == INTEGER_TYPE - || TREE_CODE(type) == REAL_TYPE - || TREE_CODE(type) == COMPLEX_TYPE - || TREE_CODE(type) == BOOLEAN_TYPE)) - { - tree decl = build_decl(BUILTINS_LOCATION, TYPE_DECL, - get_identifier_from_string(name), - type); - TYPE_NAME(type) = decl; - return this->make_type(type); - } - - tree copy = build_variant_type_copy(type); - tree decl = build_decl(location.gcc_location(), TYPE_DECL, - get_identifier_from_string(name), - copy); - DECL_ORIGINAL_TYPE(decl) = type; - TYPE_NAME(copy) = decl; - return this->make_type(copy); -} - -// Return a pointer type used as a marker for a circular type. - -Btype* -Gcc_backend::circular_pointer_type(Btype*, bool) -{ - return this->make_type(ptr_type_node); -} - -// Return whether we might be looking at a circular type. - -bool -Gcc_backend::is_circular_pointer_type(Btype* btype) -{ - return btype->get_tree() == ptr_type_node; -} - -// Return the size of a type. - -size_t -Gcc_backend::type_size(Btype* btype) -{ - tree t = btype->get_tree(); - if (t == error_mark_node) - return 1; - t = TYPE_SIZE_UNIT(t); - gcc_assert(TREE_CODE(t) == INTEGER_CST); - gcc_assert(TREE_INT_CST_HIGH(t) == 0); - unsigned HOST_WIDE_INT val_wide = TREE_INT_CST_LOW(t); - size_t ret = static_cast<size_t>(val_wide); - gcc_assert(ret == val_wide); - return ret; -} - -// Return the alignment of a type. - -size_t -Gcc_backend::type_alignment(Btype* btype) -{ - tree t = btype->get_tree(); - if (t == error_mark_node) - return 1; - return TYPE_ALIGN_UNIT(t); -} - -// Return the alignment of a struct field of type BTYPE. - -size_t -Gcc_backend::type_field_alignment(Btype* btype) -{ - tree t = btype->get_tree(); - if (t == error_mark_node) - return 1; - return go_field_alignment(t); -} - -// Return the offset of a field in a struct. - -size_t -Gcc_backend::type_field_offset(Btype* btype, size_t index) -{ - tree struct_tree = btype->get_tree(); - if (struct_tree == error_mark_node) - return 0; - gcc_assert(TREE_CODE(struct_tree) == RECORD_TYPE); - tree field = TYPE_FIELDS(struct_tree); - for (; index > 0; --index) - { - field = DECL_CHAIN(field); - gcc_assert(field != NULL_TREE); - } - HOST_WIDE_INT offset_wide = int_byte_position(field); - gcc_assert(offset_wide >= 0); - size_t ret = static_cast<size_t>(offset_wide); - gcc_assert(ret == static_cast<unsigned HOST_WIDE_INT>(offset_wide)); - return ret; -} - -// Return the zero value for a type. - -Bexpression* -Gcc_backend::zero_expression(Btype* btype) -{ - tree t = btype->get_tree(); - tree ret; - if (t == error_mark_node) - ret = error_mark_node; - else - ret = build_zero_cst(t); - return tree_to_expr(ret); -} - -// An expression as a statement. - -Bstatement* -Gcc_backend::expression_statement(Bexpression* expr) -{ - return this->make_statement(expr->get_tree()); -} - -// Variable initialization. - -Bstatement* -Gcc_backend::init_statement(Bvariable* var, Bexpression* init) -{ - tree var_tree = var->get_tree(); - tree init_tree = init->get_tree(); - if (var_tree == error_mark_node || init_tree == error_mark_node) - return this->error_statement(); - gcc_assert(TREE_CODE(var_tree) == VAR_DECL); - - // To avoid problems with GNU ld, we don't make zero-sized - // externally visible variables. That might lead us to doing an - // initialization of a zero-sized expression to a non-zero sized - // variable, or vice-versa. Avoid crashes by omitting the - // initializer. Such initializations don't mean anything anyhow. - if (int_size_in_bytes(TREE_TYPE(var_tree)) != 0 - && init_tree != NULL_TREE - && int_size_in_bytes(TREE_TYPE(init_tree)) != 0) - { - DECL_INITIAL(var_tree) = init_tree; - init_tree = NULL_TREE; - } - - tree ret = build1_loc(DECL_SOURCE_LOCATION(var_tree), DECL_EXPR, - void_type_node, var_tree); - if (init_tree != NULL_TREE) - ret = build2_loc(DECL_SOURCE_LOCATION(var_tree), COMPOUND_EXPR, - void_type_node, init_tree, ret); - - return this->make_statement(ret); -} - -// Assignment. - -Bstatement* -Gcc_backend::assignment_statement(Bexpression* lhs, Bexpression* rhs, - Location location) -{ - tree lhs_tree = lhs->get_tree(); - tree rhs_tree = rhs->get_tree(); - if (lhs_tree == error_mark_node || rhs_tree == error_mark_node) - return this->error_statement(); - - // To avoid problems with GNU ld, we don't make zero-sized - // externally visible variables. That might lead us to doing an - // assignment of a zero-sized expression to a non-zero sized - // expression; avoid crashes here by avoiding assignments of - // zero-sized expressions. Such assignments don't really mean - // anything anyhow. - if (int_size_in_bytes(TREE_TYPE(lhs_tree)) == 0 - || int_size_in_bytes(TREE_TYPE(rhs_tree)) == 0) - return this->compound_statement(this->expression_statement(lhs), - this->expression_statement(rhs)); - - // Sometimes the same unnamed Go type can be created multiple times - // and thus have multiple tree representations. Make sure this does - // not confuse the middle-end. - if (TREE_TYPE(lhs_tree) != TREE_TYPE(rhs_tree)) - { - tree lhs_type_tree = TREE_TYPE(lhs_tree); - gcc_assert(TREE_CODE(lhs_type_tree) == TREE_CODE(TREE_TYPE(rhs_tree))); - if (POINTER_TYPE_P(lhs_type_tree) - || INTEGRAL_TYPE_P(lhs_type_tree) - || SCALAR_FLOAT_TYPE_P(lhs_type_tree) - || COMPLEX_FLOAT_TYPE_P(lhs_type_tree)) - rhs_tree = fold_convert_loc(location.gcc_location(), lhs_type_tree, - rhs_tree); - else if (TREE_CODE(lhs_type_tree) == RECORD_TYPE - || TREE_CODE(lhs_type_tree) == ARRAY_TYPE) - { - gcc_assert(int_size_in_bytes(lhs_type_tree) - == int_size_in_bytes(TREE_TYPE(rhs_tree))); - rhs_tree = fold_build1_loc(location.gcc_location(), - VIEW_CONVERT_EXPR, - lhs_type_tree, rhs_tree); - } - } - - return this->make_statement(fold_build2_loc(location.gcc_location(), - MODIFY_EXPR, - void_type_node, - lhs_tree, rhs_tree)); -} - -// Return. - -Bstatement* -Gcc_backend::return_statement(Bfunction* bfunction, - const std::vector<Bexpression*>& vals, - Location location) -{ - tree fntree = bfunction->get_tree(); - if (fntree == error_mark_node) - return this->error_statement(); - tree result = DECL_RESULT(fntree); - if (result == error_mark_node) - return this->error_statement(); - tree ret; - if (vals.empty()) - ret = fold_build1_loc(location.gcc_location(), RETURN_EXPR, void_type_node, - NULL_TREE); - else if (vals.size() == 1) - { - tree val = vals.front()->get_tree(); - if (val == error_mark_node) - return this->error_statement(); - tree set = fold_build2_loc(location.gcc_location(), MODIFY_EXPR, - void_type_node, result, - vals.front()->get_tree()); - ret = fold_build1_loc(location.gcc_location(), RETURN_EXPR, - void_type_node, set); - } - else - { - // To return multiple values, copy the values into a temporary - // variable of the right structure type, and then assign the - // temporary variable to the DECL_RESULT in the return - // statement. - tree stmt_list = NULL_TREE; - tree rettype = TREE_TYPE(result); - tree rettmp = create_tmp_var(rettype, "RESULT"); - tree field = TYPE_FIELDS(rettype); - for (std::vector<Bexpression*>::const_iterator p = vals.begin(); - p != vals.end(); - p++, field = DECL_CHAIN(field)) - { - gcc_assert(field != NULL_TREE); - tree ref = fold_build3_loc(location.gcc_location(), COMPONENT_REF, - TREE_TYPE(field), rettmp, field, - NULL_TREE); - tree val = (*p)->get_tree(); - if (val == error_mark_node) - return this->error_statement(); - tree set = fold_build2_loc(location.gcc_location(), MODIFY_EXPR, - void_type_node, - ref, (*p)->get_tree()); - append_to_statement_list(set, &stmt_list); - } - gcc_assert(field == NULL_TREE); - tree set = fold_build2_loc(location.gcc_location(), MODIFY_EXPR, - void_type_node, - result, rettmp); - tree ret_expr = fold_build1_loc(location.gcc_location(), RETURN_EXPR, - void_type_node, set); - append_to_statement_list(ret_expr, &stmt_list); - ret = stmt_list; - } - return this->make_statement(ret); -} - -// If. - -Bstatement* -Gcc_backend::if_statement(Bexpression* condition, Bblock* then_block, - Bblock* else_block, Location location) -{ - tree cond_tree = condition->get_tree(); - tree then_tree = then_block->get_tree(); - tree else_tree = else_block == NULL ? NULL_TREE : else_block->get_tree(); - if (cond_tree == error_mark_node - || then_tree == error_mark_node - || else_tree == error_mark_node) - return this->error_statement(); - tree ret = build3_loc(location.gcc_location(), COND_EXPR, void_type_node, - cond_tree, then_tree, else_tree); - return this->make_statement(ret); -} - -// Switch. - -Bstatement* -Gcc_backend::switch_statement( - Bexpression* value, - const std::vector<std::vector<Bexpression*> >& cases, - const std::vector<Bstatement*>& statements, - Location switch_location) -{ - gcc_assert(cases.size() == statements.size()); - - tree stmt_list = NULL_TREE; - std::vector<std::vector<Bexpression*> >::const_iterator pc = cases.begin(); - for (std::vector<Bstatement*>::const_iterator ps = statements.begin(); - ps != statements.end(); - ++ps, ++pc) - { - if (pc->empty()) - { - source_location loc = (*ps != NULL - ? EXPR_LOCATION((*ps)->get_tree()) - : UNKNOWN_LOCATION); - tree label = create_artificial_label(loc); - tree c = build_case_label(NULL_TREE, NULL_TREE, label); - append_to_statement_list(c, &stmt_list); - } - else - { - for (std::vector<Bexpression*>::const_iterator pcv = pc->begin(); - pcv != pc->end(); - ++pcv) - { - tree t = (*pcv)->get_tree(); - if (t == error_mark_node) - return this->error_statement(); - source_location loc = EXPR_LOCATION(t); - tree label = create_artificial_label(loc); - tree c = build_case_label((*pcv)->get_tree(), NULL_TREE, label); - append_to_statement_list(c, &stmt_list); - } - } - - if (*ps != NULL) - { - tree t = (*ps)->get_tree(); - if (t == error_mark_node) - return this->error_statement(); - append_to_statement_list(t, &stmt_list); - } - } - - tree tv = value->get_tree(); - if (tv == error_mark_node) - return this->error_statement(); - tree t = build3_loc(switch_location.gcc_location(), SWITCH_EXPR, - NULL_TREE, tv, stmt_list, NULL_TREE); - return this->make_statement(t); -} - -// Pair of statements. - -Bstatement* -Gcc_backend::compound_statement(Bstatement* s1, Bstatement* s2) -{ - tree stmt_list = NULL_TREE; - tree t = s1->get_tree(); - if (t == error_mark_node) - return this->error_statement(); - append_to_statement_list(t, &stmt_list); - t = s2->get_tree(); - if (t == error_mark_node) - return this->error_statement(); - append_to_statement_list(t, &stmt_list); - return this->make_statement(stmt_list); -} - -// List of statements. - -Bstatement* -Gcc_backend::statement_list(const std::vector<Bstatement*>& statements) -{ - tree stmt_list = NULL_TREE; - for (std::vector<Bstatement*>::const_iterator p = statements.begin(); - p != statements.end(); - ++p) - { - tree t = (*p)->get_tree(); - if (t == error_mark_node) - return this->error_statement(); - append_to_statement_list(t, &stmt_list); - } - return this->make_statement(stmt_list); -} - -// Make a block. For some reason gcc uses a dual structure for -// blocks: BLOCK tree nodes and BIND_EXPR tree nodes. Since the -// BIND_EXPR node points to the BLOCK node, we store the BIND_EXPR in -// the Bblock. - -Bblock* -Gcc_backend::block(Bfunction* function, Bblock* enclosing, - const std::vector<Bvariable*>& vars, - Location start_location, - Location) -{ - tree block_tree = make_node(BLOCK); - if (enclosing == NULL) - { - // FIXME: Permitting FUNCTION to be NULL is a temporary measure - // until we have a proper representation of the init function. - tree fndecl; - if (function == NULL) - fndecl = current_function_decl; - else - fndecl = function->get_tree(); - gcc_assert(fndecl != NULL_TREE); - - // We may have already created a block for local variables when - // we take the address of a parameter. - if (DECL_INITIAL(fndecl) == NULL_TREE) - { - BLOCK_SUPERCONTEXT(block_tree) = fndecl; - DECL_INITIAL(fndecl) = block_tree; - } - else - { - tree superblock_tree = DECL_INITIAL(fndecl); - BLOCK_SUPERCONTEXT(block_tree) = superblock_tree; - tree* pp; - for (pp = &BLOCK_SUBBLOCKS(superblock_tree); - *pp != NULL_TREE; - pp = &BLOCK_CHAIN(*pp)) - ; - *pp = block_tree; - } - } - else - { - tree superbind_tree = enclosing->get_tree(); - tree superblock_tree = BIND_EXPR_BLOCK(superbind_tree); - gcc_assert(TREE_CODE(superblock_tree) == BLOCK); - - BLOCK_SUPERCONTEXT(block_tree) = superblock_tree; - tree* pp; - for (pp = &BLOCK_SUBBLOCKS(superblock_tree); - *pp != NULL_TREE; - pp = &BLOCK_CHAIN(*pp)) - ; - *pp = block_tree; - } - - tree* pp = &BLOCK_VARS(block_tree); - for (std::vector<Bvariable*>::const_iterator pv = vars.begin(); - pv != vars.end(); - ++pv) - { - *pp = (*pv)->get_tree(); - if (*pp != error_mark_node) - pp = &DECL_CHAIN(*pp); - } - *pp = NULL_TREE; - - TREE_USED(block_tree) = 1; - - tree bind_tree = build3_loc(start_location.gcc_location(), BIND_EXPR, - void_type_node, BLOCK_VARS(block_tree), - NULL_TREE, block_tree); - TREE_SIDE_EFFECTS(bind_tree) = 1; - - return new Bblock(bind_tree); -} - -// Add statements to a block. - -void -Gcc_backend::block_add_statements(Bblock* bblock, - const std::vector<Bstatement*>& statements) -{ - tree stmt_list = NULL_TREE; - for (std::vector<Bstatement*>::const_iterator p = statements.begin(); - p != statements.end(); - ++p) - { - tree s = (*p)->get_tree(); - if (s != error_mark_node) - append_to_statement_list(s, &stmt_list); - } - - tree bind_tree = bblock->get_tree(); - gcc_assert(TREE_CODE(bind_tree) == BIND_EXPR); - BIND_EXPR_BODY(bind_tree) = stmt_list; -} - -// Return a block as a statement. - -Bstatement* -Gcc_backend::block_statement(Bblock* bblock) -{ - tree bind_tree = bblock->get_tree(); - gcc_assert(TREE_CODE(bind_tree) == BIND_EXPR); - return this->make_statement(bind_tree); -} - -// This is not static because we declare it with GTY(()) in go-c.h. -tree go_non_zero_struct; - -// Return a type corresponding to TYPE with non-zero size. - -tree -Gcc_backend::non_zero_size_type(tree type) -{ - if (int_size_in_bytes(type) != 0) - return type; - - switch (TREE_CODE(type)) - { - case RECORD_TYPE: - { - if (go_non_zero_struct == NULL_TREE) - { - type = make_node(RECORD_TYPE); - tree field = build_decl(UNKNOWN_LOCATION, FIELD_DECL, - get_identifier("dummy"), - boolean_type_node); - DECL_CONTEXT(field) = type; - TYPE_FIELDS(type) = field; - layout_type(type); - go_non_zero_struct = type; - } - return go_non_zero_struct; - } - - case ARRAY_TYPE: - { - tree element_type = non_zero_size_type(TREE_TYPE(type)); - return build_array_type_nelts(element_type, 1); - } - - default: - gcc_unreachable(); - } - - gcc_unreachable(); -} - -// Make a global variable. - -Bvariable* -Gcc_backend::global_variable(const std::string& package_name, - const std::string& pkgpath, - const std::string& name, - Btype* btype, - bool is_external, - bool is_hidden, - bool in_unique_section, - Location location) -{ - tree type_tree = btype->get_tree(); - if (type_tree == error_mark_node) - return this->error_variable(); - - // The GNU linker does not like dynamic variables with zero size. - if ((is_external || !is_hidden) && int_size_in_bytes(type_tree) == 0) - type_tree = this->non_zero_size_type(type_tree); - - std::string var_name(package_name); - var_name.push_back('.'); - var_name.append(name); - tree decl = build_decl(location.gcc_location(), VAR_DECL, - get_identifier_from_string(var_name), - type_tree); - if (is_external) - DECL_EXTERNAL(decl) = 1; - else - TREE_STATIC(decl) = 1; - if (!is_hidden) - { - TREE_PUBLIC(decl) = 1; - - std::string asm_name(pkgpath); - asm_name.push_back('.'); - asm_name.append(name); - SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name)); - } - TREE_USED(decl) = 1; - - if (in_unique_section) - resolve_unique_section (decl, 0, 1); - - go_preserve_from_gc(decl); - - return new Bvariable(decl); -} - -// Set the initial value of a global variable. - -void -Gcc_backend::global_variable_set_init(Bvariable* var, Bexpression* expr) -{ - tree expr_tree = expr->get_tree(); - if (expr_tree == error_mark_node) - return; - gcc_assert(TREE_CONSTANT(expr_tree)); - tree var_decl = var->get_tree(); - if (var_decl == error_mark_node) - return; - DECL_INITIAL(var_decl) = expr_tree; - - // If this variable goes in a unique section, it may need to go into - // a different one now that DECL_INITIAL is set. - if (DECL_HAS_IMPLICIT_SECTION_NAME_P (var_decl)) - { - DECL_SECTION_NAME (var_decl) = NULL_TREE; - resolve_unique_section (var_decl, - compute_reloc_for_constant (expr_tree), - 1); - } -} - -// Make a local variable. - -Bvariable* -Gcc_backend::local_variable(Bfunction* function, const std::string& name, - Btype* btype, bool is_address_taken, - Location location) -{ - tree type_tree = btype->get_tree(); - if (type_tree == error_mark_node) - return this->error_variable(); - tree decl = build_decl(location.gcc_location(), VAR_DECL, - get_identifier_from_string(name), - type_tree); - DECL_CONTEXT(decl) = function->get_tree(); - TREE_USED(decl) = 1; - if (is_address_taken) - TREE_ADDRESSABLE(decl) = 1; - go_preserve_from_gc(decl); - return new Bvariable(decl); -} - -// Make a function parameter variable. - -Bvariable* -Gcc_backend::parameter_variable(Bfunction* function, const std::string& name, - Btype* btype, bool is_address_taken, - Location location) -{ - tree type_tree = btype->get_tree(); - if (type_tree == error_mark_node) - return this->error_variable(); - tree decl = build_decl(location.gcc_location(), PARM_DECL, - get_identifier_from_string(name), - type_tree); - DECL_CONTEXT(decl) = function->get_tree(); - DECL_ARG_TYPE(decl) = type_tree; - TREE_USED(decl) = 1; - if (is_address_taken) - TREE_ADDRESSABLE(decl) = 1; - go_preserve_from_gc(decl); - return new Bvariable(decl); -} - -// Make a temporary variable. - -Bvariable* -Gcc_backend::temporary_variable(Bfunction* function, Bblock* bblock, - Btype* btype, Bexpression* binit, - bool is_address_taken, - Location location, - Bstatement** pstatement) -{ - tree type_tree = btype->get_tree(); - tree init_tree = binit == NULL ? NULL_TREE : binit->get_tree(); - if (type_tree == error_mark_node || init_tree == error_mark_node) - { - *pstatement = this->error_statement(); - return this->error_variable(); - } - - tree var; - // We can only use create_tmp_var if the type is not addressable. - if (!TREE_ADDRESSABLE(type_tree)) - var = create_tmp_var(type_tree, "GOTMP"); - else - { - gcc_assert(bblock != NULL); - var = build_decl(location.gcc_location(), VAR_DECL, - create_tmp_var_name("GOTMP"), - type_tree); - DECL_ARTIFICIAL(var) = 1; - DECL_IGNORED_P(var) = 1; - TREE_USED(var) = 1; - // FIXME: Permitting function to be NULL here is a temporary - // measure until we have a proper representation of the init - // function. - if (function != NULL) - DECL_CONTEXT(var) = function->get_tree(); - else - { - gcc_assert(current_function_decl != NULL_TREE); - DECL_CONTEXT(var) = current_function_decl; - } - - // We have to add this variable to the BLOCK and the BIND_EXPR. - tree bind_tree = bblock->get_tree(); - gcc_assert(TREE_CODE(bind_tree) == BIND_EXPR); - tree block_tree = BIND_EXPR_BLOCK(bind_tree); - gcc_assert(TREE_CODE(block_tree) == BLOCK); - DECL_CHAIN(var) = BLOCK_VARS(block_tree); - BLOCK_VARS(block_tree) = var; - BIND_EXPR_VARS(bind_tree) = BLOCK_VARS(block_tree); - } - - if (init_tree != NULL_TREE) - DECL_INITIAL(var) = fold_convert_loc(location.gcc_location(), type_tree, - init_tree); - - if (is_address_taken) - TREE_ADDRESSABLE(var) = 1; - - *pstatement = this->make_statement(build1_loc(location.gcc_location(), - DECL_EXPR, - void_type_node, var)); - return new Bvariable(var); -} - -// Create a named immutable initialized data structure. - -Bvariable* -Gcc_backend::immutable_struct(const std::string& name, bool, Btype* btype, - Location location) -{ - tree type_tree = btype->get_tree(); - if (type_tree == error_mark_node) - return this->error_variable(); - gcc_assert(TREE_CODE(type_tree) == RECORD_TYPE); - tree decl = build_decl(location.gcc_location(), VAR_DECL, - get_identifier_from_string(name), - build_qualified_type(type_tree, TYPE_QUAL_CONST)); - TREE_STATIC(decl) = 1; - TREE_READONLY(decl) = 1; - TREE_CONSTANT(decl) = 1; - TREE_USED(decl) = 1; - DECL_ARTIFICIAL(decl) = 1; - - // We don't call rest_of_decl_compilation until we have the - // initializer. - - go_preserve_from_gc(decl); - return new Bvariable(decl); -} - -// Set the initializer for a variable created by immutable_struct. -// This is where we finish compiling the variable. - -void -Gcc_backend::immutable_struct_set_init(Bvariable* var, const std::string&, - bool is_common, Btype*, - Location, - Bexpression* initializer) -{ - tree decl = var->get_tree(); - tree init_tree = initializer->get_tree(); - if (decl == error_mark_node || init_tree == error_mark_node) - return; - - DECL_INITIAL(decl) = init_tree; - - // We can't call make_decl_one_only until we set DECL_INITIAL. - if (!is_common) - TREE_PUBLIC(decl) = 1; - else - { - make_decl_one_only(decl, DECL_ASSEMBLER_NAME(decl)); - resolve_unique_section(decl, 1, 0); - } - - rest_of_decl_compilation(decl, 1, 0); -} - -// Return a reference to an immutable initialized data structure -// defined in another package. - -Bvariable* -Gcc_backend::immutable_struct_reference(const std::string& name, Btype* btype, - Location location) -{ - tree type_tree = btype->get_tree(); - if (type_tree == error_mark_node) - return this->error_variable(); - gcc_assert(TREE_CODE(type_tree) == RECORD_TYPE); - tree decl = build_decl(location.gcc_location(), VAR_DECL, - get_identifier_from_string(name), - build_qualified_type(type_tree, TYPE_QUAL_CONST)); - TREE_READONLY(decl) = 1; - TREE_CONSTANT(decl) = 1; - DECL_ARTIFICIAL(decl) = 1; - TREE_PUBLIC(decl) = 1; - DECL_EXTERNAL(decl) = 1; - go_preserve_from_gc(decl); - return new Bvariable(decl); -} - -// Make a label. - -Blabel* -Gcc_backend::label(Bfunction* function, const std::string& name, - Location location) -{ - tree decl; - if (name.empty()) - decl = create_artificial_label(location.gcc_location()); - else - { - tree id = get_identifier_from_string(name); - decl = build_decl(location.gcc_location(), LABEL_DECL, id, - void_type_node); - DECL_CONTEXT(decl) = function->get_tree(); - } - return new Blabel(decl); -} - -// Make a statement which defines a label. - -Bstatement* -Gcc_backend::label_definition_statement(Blabel* label) -{ - tree lab = label->get_tree(); - tree ret = fold_build1_loc(DECL_SOURCE_LOCATION(lab), LABEL_EXPR, - void_type_node, lab); - return this->make_statement(ret); -} - -// Make a goto statement. - -Bstatement* -Gcc_backend::goto_statement(Blabel* label, Location location) -{ - tree lab = label->get_tree(); - tree ret = fold_build1_loc(location.gcc_location(), GOTO_EXPR, void_type_node, - lab); - return this->make_statement(ret); -} - -// Get the address of a label. - -Bexpression* -Gcc_backend::label_address(Blabel* label, Location location) -{ - tree lab = label->get_tree(); - TREE_USED(lab) = 1; - TREE_ADDRESSABLE(lab) = 1; - tree ret = fold_convert_loc(location.gcc_location(), ptr_type_node, - build_fold_addr_expr_loc(location.gcc_location(), - lab)); - return this->make_expression(ret); -} - -// The single backend. - -static Gcc_backend gcc_backend; - -// Return the backend generator. - -Backend* -go_get_backend() -{ - return &gcc_backend; -} - -// FIXME: Temporary functions while converting to the new backend -// interface. - -Btype* -tree_to_type(tree t) -{ - return new Btype(t); -} - -Bexpression* -tree_to_expr(tree t) -{ - return new Bexpression(t); -} - -Bstatement* -tree_to_stat(tree t) -{ - return new Bstatement(t); -} - -Bfunction* -tree_to_function(tree t) -{ - return new Bfunction(t); -} - -Bblock* -tree_to_block(tree t) -{ - gcc_assert(TREE_CODE(t) == BIND_EXPR); - return new Bblock(t); -} - -tree -type_to_tree(Btype* bt) -{ - return bt->get_tree(); -} - -tree -expr_to_tree(Bexpression* be) -{ - return be->get_tree(); -} - -tree -stat_to_tree(Bstatement* bs) -{ - return bs->get_tree(); -} - -tree -block_to_tree(Bblock* bb) -{ - return bb->get_tree(); -} - -tree -var_to_tree(Bvariable* bv) -{ - return bv->get_tree(); -} diff --git a/gcc-4.8.1/gcc/go/go-lang.c b/gcc-4.8.1/gcc/go/go-lang.c deleted file mode 100644 index 659cd8ef7..000000000 --- a/gcc-4.8.1/gcc/go/go-lang.c +++ /dev/null @@ -1,493 +0,0 @@ -/* go-lang.c -- Go frontend gcc interface. - Copyright (C) 2009-2013 Free Software Foundation, Inc. - -This file is part of GCC. - -GCC 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, or (at your option) any later -version. - -GCC 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 GCC; see the file COPYING3. If not see -<http://www.gnu.org/licenses/>. */ - -#include "config.h" -#include "system.h" -#include "ansidecl.h" -#include "coretypes.h" -#include "opts.h" -#include "tree.h" -#include "gimple.h" -#include "ggc.h" -#include "toplev.h" -#include "debug.h" -#include "options.h" -#include "flags.h" -#include "convert.h" -#include "diagnostic.h" -#include "langhooks.h" -#include "langhooks-def.h" -#include "except.h" -#include "target.h" -#include "common/common-target.h" - -#include <mpfr.h> - -#include "go-c.h" - -/* Language-dependent contents of a type. */ - -struct GTY(()) lang_type -{ - char dummy; -}; - -/* Language-dependent contents of a decl. */ - -struct GTY((variable_size)) lang_decl -{ - char dummy; -}; - -/* Language-dependent contents of an identifier. This must include a - tree_identifier. */ - -struct GTY(()) lang_identifier -{ - struct tree_identifier common; -}; - -/* The resulting tree type. */ - -union GTY((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"), - chain_next ("CODE_CONTAINS_STRUCT (TREE_CODE (&%h.generic), TS_COMMON) ? ((union lang_tree_node *) TREE_CHAIN (&%h.generic)) : NULL"))) -lang_tree_node -{ - union tree_node GTY((tag ("0"), - desc ("tree_node_structure (&%h)"))) generic; - struct lang_identifier GTY((tag ("1"))) identifier; -}; - -/* We don't use language_function. */ - -struct GTY(()) language_function -{ - int dummy; -}; - -/* Option information we need to pass to go_create_gogo. */ - -static const char *go_pkgpath = NULL; -static const char *go_prefix = NULL; -static const char *go_relative_import_path = NULL; - -/* Language hooks. */ - -static bool -go_langhook_init (void) -{ - build_common_tree_nodes (false, false); - - /* I don't know why this has to be done explicitly. */ - void_list_node = build_tree_list (NULL_TREE, void_type_node); - - /* We must create the gogo IR after calling build_common_tree_nodes - (because Gogo::define_builtin_function_trees refers indirectly - to, e.g., unsigned_char_type_node) but before calling - build_common_builtin_nodes (because it calls, indirectly, - go_type_for_size). */ - go_create_gogo (INT_TYPE_SIZE, POINTER_SIZE, go_pkgpath, go_prefix, - go_relative_import_path); - - build_common_builtin_nodes (); - - /* The default precision for floating point numbers. This is used - for floating point constants with abstract type. This may - eventually be controllable by a command line option. */ - mpfr_set_default_prec (256); - - /* Go uses exceptions. */ - using_eh_for_cleanups (); - - return true; -} - -/* The option mask. */ - -static unsigned int -go_langhook_option_lang_mask (void) -{ - return CL_Go; -} - -/* Initialize the options structure. */ - -static void -go_langhook_init_options_struct (struct gcc_options *opts) -{ - /* Go says that signed overflow is precisely defined. */ - opts->x_flag_wrapv = 1; - - /* We default to using strict aliasing, since Go pointers are safe. - This is turned off for code that imports the "unsafe" package, - because using unsafe.pointer violates C style aliasing - requirements. */ - opts->x_flag_strict_aliasing = 1; - - /* Default to avoiding range issues for complex multiply and - divide. */ - opts->x_flag_complex_method = 2; - - /* The builtin math functions should not set errno. */ - opts->x_flag_errno_math = 0; - opts->frontend_set_flag_errno_math = true; - - /* We turn on stack splitting if we can. */ - if (targetm_common.supports_split_stack (false, opts)) - opts->x_flag_split_stack = 1; - - /* Exceptions are used to handle recovering from panics. */ - opts->x_flag_exceptions = 1; - opts->x_flag_non_call_exceptions = 1; -} - -/* Infrastructure for a vector of char * pointers. */ - -typedef const char *go_char_p; - -/* The list of directories to search after all the Go specific - directories have been searched. */ - -static vec<go_char_p> go_search_dirs; - -/* Handle Go specific options. Return 0 if we didn't do anything. */ - -static bool -go_langhook_handle_option ( - size_t scode, - const char *arg, - int value ATTRIBUTE_UNUSED, - int kind ATTRIBUTE_UNUSED, - location_t loc ATTRIBUTE_UNUSED, - const struct cl_option_handlers *handlers ATTRIBUTE_UNUSED) -{ - enum opt_code code = (enum opt_code) scode; - bool ret = true; - - switch (code) - { - case OPT_I: - go_add_search_path (arg); - break; - - case OPT_L: - /* A -L option is assumed to come from the compiler driver. - This is a system directory. We search the following - directories, if they exist, before this one: - dir/go/VERSION - dir/go/VERSION/MACHINE - This is like include/c++. */ - { - static const char dir_separator_str[] = { DIR_SEPARATOR, 0 }; - size_t len; - char *p; - struct stat st; - - len = strlen (arg); - p = XALLOCAVEC (char, - (len + sizeof "go" + sizeof DEFAULT_TARGET_VERSION - + sizeof DEFAULT_TARGET_MACHINE + 3)); - strcpy (p, arg); - if (len > 0 && !IS_DIR_SEPARATOR (p[len - 1])) - strcat (p, dir_separator_str); - strcat (p, "go"); - strcat (p, dir_separator_str); - strcat (p, DEFAULT_TARGET_VERSION); - if (stat (p, &st) == 0 && S_ISDIR (st.st_mode)) - { - go_add_search_path (p); - strcat (p, dir_separator_str); - strcat (p, DEFAULT_TARGET_MACHINE); - if (stat (p, &st) == 0 && S_ISDIR (st.st_mode)) - go_add_search_path (p); - } - - /* Search ARG too, but only after we've searched to Go - specific directories for all -L arguments. */ - go_search_dirs.safe_push (arg); - } - break; - - case OPT_fgo_dump_: - ret = go_enable_dump (arg) ? true : false; - break; - - case OPT_fgo_optimize_: - ret = go_enable_optimize (arg) ? true : false; - break; - - case OPT_fgo_pkgpath_: - go_pkgpath = arg; - break; - - case OPT_fgo_prefix_: - go_prefix = arg; - break; - - case OPT_fgo_relative_import_path_: - go_relative_import_path = arg; - break; - - default: - /* Just return 1 to indicate that the option is valid. */ - break; - } - - return ret; -} - -/* Run after parsing options. */ - -static bool -go_langhook_post_options (const char **pfilename ATTRIBUTE_UNUSED) -{ - unsigned int ix; - const char *dir; - - gcc_assert (num_in_fnames > 0); - - FOR_EACH_VEC_ELT (go_search_dirs, ix, dir) - go_add_search_path (dir); - go_search_dirs.release (); - - if (flag_excess_precision_cmdline == EXCESS_PRECISION_DEFAULT) - flag_excess_precision_cmdline = EXCESS_PRECISION_STANDARD; - - /* Returning false means that the backend should be used. */ - return false; -} - -static void -go_langhook_parse_file (void) -{ - go_parse_input_files (in_fnames, num_in_fnames, flag_syntax_only, - go_require_return_statement); -} - -static tree -go_langhook_type_for_size (unsigned int bits, int unsignedp) -{ - return go_type_for_size (bits, unsignedp); -} - -static tree -go_langhook_type_for_mode (enum machine_mode mode, int unsignedp) -{ - tree type; - /* Go has no vector types. Build them here. FIXME: It does not - make sense for the middle-end to ask the frontend for a type - which the frontend does not support. However, at least for now - it is required. See PR 46805. */ - if (VECTOR_MODE_P (mode)) - { - tree inner; - - inner = go_langhook_type_for_mode (GET_MODE_INNER (mode), unsignedp); - if (inner != NULL_TREE) - return build_vector_type_for_mode (inner, mode); - return NULL_TREE; - } - - type = go_type_for_mode (mode, unsignedp); - if (type) - return type; - -#if HOST_BITS_PER_WIDE_INT >= 64 - /* The middle-end and some backends rely on TImode being supported - for 64-bit HWI. */ - if (mode == TImode) - { - type = build_nonstandard_integer_type (GET_MODE_BITSIZE (TImode), - unsignedp); - if (type && TYPE_MODE (type) == TImode) - return type; - } -#endif - return NULL_TREE; -} - -/* Record a builtin function. We just ignore builtin functions. */ - -static tree -go_langhook_builtin_function (tree decl) -{ - return decl; -} - -/* Return true if we are in the global binding level. */ - -static bool -go_langhook_global_bindings_p (void) -{ - return current_function_decl == NULL_TREE; -} - -/* Push a declaration into the current binding level. We can't - usefully implement this since we don't want to convert from tree - back to one of our internal data structures. I think the only way - this is used is to record a decl which is to be returned by - getdecls, and we could implement it for that purpose if - necessary. */ - -static tree -go_langhook_pushdecl (tree decl ATTRIBUTE_UNUSED) -{ - gcc_unreachable (); -} - -/* This hook is used to get the current list of declarations as trees. - We don't support that; instead we use the write_globals hook. This - can't simply crash because it is called by -gstabs. */ - -static tree -go_langhook_getdecls (void) -{ - return NULL; -} - -/* Write out globals. */ - -static void -go_langhook_write_globals (void) -{ - go_write_globals (); -} - -/* Go specific gimplification. We need to gimplify - CALL_EXPR_STATIC_CHAIN, because the gimplifier doesn't handle - it. */ - -static int -go_langhook_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) -{ - if (TREE_CODE (*expr_p) == CALL_EXPR - && CALL_EXPR_STATIC_CHAIN (*expr_p) != NULL_TREE) - gimplify_expr (&CALL_EXPR_STATIC_CHAIN (*expr_p), pre_p, post_p, - is_gimple_val, fb_rvalue); - return GS_UNHANDLED; -} - -/* Return a decl for the exception personality function. The function - itself is implemented in libgo/runtime/go-unwind.c. */ - -static tree -go_langhook_eh_personality (void) -{ - static tree personality_decl; - if (personality_decl == NULL_TREE) - { - personality_decl = build_personality_function ("gccgo"); - go_preserve_from_gc (personality_decl); - } - return personality_decl; -} - -/* Functions called directly by the generic backend. */ - -tree -convert (tree type, tree expr) -{ - if (type == error_mark_node - || expr == error_mark_node - || TREE_TYPE (expr) == error_mark_node) - return error_mark_node; - - if (type == TREE_TYPE (expr)) - return expr; - - if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (expr))) - return fold_convert (type, expr); - - switch (TREE_CODE (type)) - { - case VOID_TYPE: - case BOOLEAN_TYPE: - return fold_convert (type, expr); - case INTEGER_TYPE: - return fold (convert_to_integer (type, expr)); - case POINTER_TYPE: - return fold (convert_to_pointer (type, expr)); - case REAL_TYPE: - return fold (convert_to_real (type, expr)); - case COMPLEX_TYPE: - return fold (convert_to_complex (type, expr)); - default: - break; - } - - gcc_unreachable (); -} - -/* FIXME: This is a hack to preserve trees that we create from the - garbage collector. */ - -static GTY(()) tree go_gc_root; - -void -go_preserve_from_gc (tree t) -{ - go_gc_root = tree_cons (NULL_TREE, t, go_gc_root); -} - -/* Convert an identifier for use in an error message. */ - -const char * -go_localize_identifier (const char *ident) -{ - return identifier_to_locale (ident); -} - -#undef LANG_HOOKS_NAME -#undef LANG_HOOKS_INIT -#undef LANG_HOOKS_OPTION_LANG_MASK -#undef LANG_HOOKS_INIT_OPTIONS_STRUCT -#undef LANG_HOOKS_HANDLE_OPTION -#undef LANG_HOOKS_POST_OPTIONS -#undef LANG_HOOKS_PARSE_FILE -#undef LANG_HOOKS_TYPE_FOR_MODE -#undef LANG_HOOKS_TYPE_FOR_SIZE -#undef LANG_HOOKS_BUILTIN_FUNCTION -#undef LANG_HOOKS_GLOBAL_BINDINGS_P -#undef LANG_HOOKS_PUSHDECL -#undef LANG_HOOKS_GETDECLS -#undef LANG_HOOKS_WRITE_GLOBALS -#undef LANG_HOOKS_GIMPLIFY_EXPR -#undef LANG_HOOKS_EH_PERSONALITY - -#define LANG_HOOKS_NAME "GNU Go" -#define LANG_HOOKS_INIT go_langhook_init -#define LANG_HOOKS_OPTION_LANG_MASK go_langhook_option_lang_mask -#define LANG_HOOKS_INIT_OPTIONS_STRUCT go_langhook_init_options_struct -#define LANG_HOOKS_HANDLE_OPTION go_langhook_handle_option -#define LANG_HOOKS_POST_OPTIONS go_langhook_post_options -#define LANG_HOOKS_PARSE_FILE go_langhook_parse_file -#define LANG_HOOKS_TYPE_FOR_MODE go_langhook_type_for_mode -#define LANG_HOOKS_TYPE_FOR_SIZE go_langhook_type_for_size -#define LANG_HOOKS_BUILTIN_FUNCTION go_langhook_builtin_function -#define LANG_HOOKS_GLOBAL_BINDINGS_P go_langhook_global_bindings_p -#define LANG_HOOKS_PUSHDECL go_langhook_pushdecl -#define LANG_HOOKS_GETDECLS go_langhook_getdecls -#define LANG_HOOKS_WRITE_GLOBALS go_langhook_write_globals -#define LANG_HOOKS_GIMPLIFY_EXPR go_langhook_gimplify_expr -#define LANG_HOOKS_EH_PERSONALITY go_langhook_eh_personality - -struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; - -#include "gt-go-go-lang.h" -#include "gtype-go.h" diff --git a/gcc-4.8.1/gcc/go/go-linemap.cc b/gcc-4.8.1/gcc/go/go-linemap.cc deleted file mode 100644 index b41559ed4..000000000 --- a/gcc-4.8.1/gcc/go/go-linemap.cc +++ /dev/null @@ -1,126 +0,0 @@ -// go-linemap.cc -- GCC implementation of Linemap. - -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "go-linemap.h" - -// This class implements the Linemap interface defined by the -// frontend. - -class Gcc_linemap : public Linemap -{ - public: - Gcc_linemap() - : Linemap(), - in_file_(false) - { } - - void - start_file(const char* file_name, unsigned int line_begin); - - void - start_line(unsigned int line_number, unsigned int line_size); - - Location - get_location(unsigned int column); - - void - stop(); - - protected: - Location - get_predeclared_location(); - - Location - get_unknown_location(); - - bool - is_predeclared(Location); - - bool - is_unknown(Location); - - private: - // Whether we are currently reading a file. - bool in_file_; -}; - -Linemap* Linemap::instance_ = NULL; - -// Start getting locations from a new file. - -void -Gcc_linemap::start_file(const char *file_name, unsigned line_begin) -{ - if (this->in_file_) - linemap_add(line_table, LC_LEAVE, 0, NULL, 0); - linemap_add(line_table, LC_ENTER, 0, file_name, line_begin); - this->in_file_ = true; -} - -// Stop getting locations. - -void -Gcc_linemap::stop() -{ - linemap_add(line_table, LC_LEAVE, 0, NULL, 0); - this->in_file_ = false; -} - -// Start a new line. - -void -Gcc_linemap::start_line(unsigned lineno, unsigned linesize) -{ - linemap_line_start(line_table, lineno, linesize); -} - -// Get a location. - -Location -Gcc_linemap::get_location(unsigned column) -{ - return Location(linemap_position_for_column(line_table, column)); -} - -// Get the unknown location. - -Location -Gcc_linemap::get_unknown_location() -{ - return Location(UNKNOWN_LOCATION); -} - -// Get the predeclared location. - -Location -Gcc_linemap::get_predeclared_location() -{ - return Location(BUILTINS_LOCATION); -} - -// Return whether a location is the predeclared location. - -bool -Gcc_linemap::is_predeclared(Location loc) -{ - return loc.gcc_location() == BUILTINS_LOCATION; -} - -// Return whether a location is the unknown location. - -bool -Gcc_linemap::is_unknown(Location loc) -{ - return loc.gcc_location() == UNKNOWN_LOCATION; -} - -// Return the Linemap to use for the gcc backend. - -Linemap* -go_get_linemap() -{ - return new Gcc_linemap; -} diff --git a/gcc-4.8.1/gcc/go/go-location.h b/gcc-4.8.1/gcc/go/go-location.h deleted file mode 100644 index f2731d968..000000000 --- a/gcc-4.8.1/gcc/go/go-location.h +++ /dev/null @@ -1,45 +0,0 @@ -// go-location.h -- GCC specific Location declaration. -*- C++ -*- - -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#ifndef GO_LOCATION_H -#define GO_LOCATION_H - -#include "go-system.h" - -// A location in an input source file. - -class Location -{ - public: - Location() - : gcc_loc_(UNKNOWN_LOCATION) - { } - - explicit Location(source_location loc) - : gcc_loc_(loc) - { } - - source_location - gcc_location() const - { return this->gcc_loc_; } - - // Temporary hack till error_at and warning_at can deal with a Location. - operator source_location() const - { return this->gcc_loc_; } - - private: - source_location gcc_loc_; -}; - -// The Go frontend requires the ability to compare Locations. - -inline bool -operator<(Location loca, Location locb) -{ - return loca.gcc_location() < locb.gcc_location(); -} - -#endif // !defined(GO_LOCATION_H) diff --git a/gcc-4.8.1/gcc/go/go-system.h b/gcc-4.8.1/gcc/go/go-system.h deleted file mode 100644 index cc924f1b1..000000000 --- a/gcc-4.8.1/gcc/go/go-system.h +++ /dev/null @@ -1,142 +0,0 @@ -// go-system.h -- Go frontend inclusion of gcc header files -*- C++ -*- -// Copyright (C) 2009-2013 Free Software Foundation, Inc. - -// This file is part of GCC. - -// GCC 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, or (at your option) any later -// version. - -// GCC 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 GCC; see the file COPYING3. If not see -// <http://www.gnu.org/licenses/>. - -#ifndef GO_SYSTEM_H -#define GO_SYSTEM_H - -#include "config.h" - -// These must be included before the #poison declarations in system.h. - -#include <algorithm> -#include <string> -#include <list> -#include <map> -#include <set> -#include <vector> - -#if defined(HAVE_UNORDERED_MAP) - -# include <unordered_map> -# include <unordered_set> - -# define Unordered_map(KEYTYPE, VALTYPE) \ - std::unordered_map<KEYTYPE, VALTYPE> - -# define Unordered_map_hash(KEYTYPE, VALTYPE, HASHFN, EQFN) \ - std::unordered_map<KEYTYPE, VALTYPE, HASHFN, EQFN> - -# define Unordered_set(KEYTYPE) \ - std::unordered_set<KEYTYPE> - -# define Unordered_set_hash(KEYTYPE, HASHFN, EQFN) \ - std::unordered_set<KEYTYPE, HASHFN, EQFN> - -#elif defined(HAVE_TR1_UNORDERED_MAP) - -# include <tr1/unordered_map> -# include <tr1/unordered_set> - -# define Unordered_map(KEYTYPE, VALTYPE) \ - std::tr1::unordered_map<KEYTYPE, VALTYPE> - -# define Unordered_map_hash(KEYTYPE, VALTYPE, HASHFN, EQFN) \ - std::tr1::unordered_map<KEYTYPE, VALTYPE, HASHFN, EQFN> - -# define Unordered_set(KEYTYPE) \ - std::tr1::unordered_set<KEYTYPE> - -# define Unordered_set_hash(KEYTYPE, HASHFN, EQFN) \ - std::tr1::unordered_set<KEYTYPE, HASHFN, EQFN> - -#elif defined(HAVE_EXT_HASH_MAP) - -# include <ext/hash_map> -# include <ext/hash_set> - -# define Unordered_map(KEYTYPE, VALTYPE) \ - __gnu_cxx::hash_map<KEYTYPE, VALTYPE> - -# define Unordered_map_hash(KEYTYPE, VALTYPE, HASHFN, EQFN) \ - __gnu_cxx::hash_map<KEYTYPE, VALTYPE, HASHFN, EQFN> - -# define Unordered_set(KEYTYPE) \ - __gnu_cxx::hash_set<KEYTYPE> - -# define Unordered_set_hash(KEYTYPE, HASHFN, EQFN) \ - __gnu_cxx::hash_set<KEYTYPE, HASHFN, EQFN> - -// Provide hash functions for strings and pointers. - -namespace __gnu_cxx -{ - -template<> -struct hash<std::string> -{ - size_t - operator()(std::string s) const - { return __stl_hash_string(s.c_str()); } -}; - -template<typename T> -struct hash<T*> -{ - size_t - operator()(T* p) const - { return reinterpret_cast<size_t>(p); } -}; - -} - -#else - -# define Unordered_map(KEYTYPE, VALTYPE) \ - std::map<KEYTYPE, VALTYPE> - -# define Unordered_set(KEYTYPE) \ - std::set<KEYTYPE> - -// We could make this work by writing an adapter class which -// implemented operator< in terms of the hash function. -# error "requires hash table type" - -#endif - -// We don't really need iostream, but some versions of gmp.h include -// it when compiled with C++, which means that we need to include it -// before the macro magic of safe-ctype.h, which is included by -// system.h. -#include <iostream> - -#include "system.h" -#include "ansidecl.h" -#include "coretypes.h" - -#include "diagnostic-core.h" /* For error_at and friends. */ -#include "input.h" /* For source_location. */ -#include "intl.h" /* For _(). */ - -// When using gcc, go_assert is just gcc_assert. -#define go_assert(EXPR) gcc_assert(EXPR) - -// When using gcc, go_unreachable is just gcc_unreachable. -#define go_unreachable() gcc_unreachable() - -#endif // !defined(GO_SYSTEM_H) diff --git a/gcc-4.8.1/gcc/go/gofrontend/LICENSE b/gcc-4.8.1/gcc/go/gofrontend/LICENSE deleted file mode 100644 index 6a66aea5e..000000000 --- a/gcc-4.8.1/gcc/go/gofrontend/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2009 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/gcc-4.8.1/gcc/go/gofrontend/PATENTS b/gcc-4.8.1/gcc/go/gofrontend/PATENTS deleted file mode 100644 index 733099041..000000000 --- a/gcc-4.8.1/gcc/go/gofrontend/PATENTS +++ /dev/null @@ -1,22 +0,0 @@ -Additional IP Rights Grant (Patents) - -"This implementation" means the copyrightable works distributed by -Google as part of the Go project. - -Google hereby grants to You a perpetual, worldwide, non-exclusive, -no-charge, royalty-free, irrevocable (except as stated in this section) -patent license to make, have made, use, offer to sell, sell, import, -transfer and otherwise run, modify and propagate the contents of this -implementation of Go, where such license applies only to those patent -claims, both currently owned or controlled by Google and acquired in -the future, licensable by Google that are necessarily infringed by this -implementation of Go. This grant does not include claims that would be -infringed only as a consequence of further modification of this -implementation. If you or your agent or exclusive licensee institute or -order or agree to the institution of patent litigation against any -entity (including a cross-claim or counterclaim in a lawsuit) alleging -that this implementation of Go or any code incorporated within this -implementation of Go constitutes direct or contributory patent -infringement, or inducement of patent infringement, then any patent -rights granted to you under this License for this implementation of Go -shall terminate as of the date such litigation is filed. diff --git a/gcc-4.8.1/gcc/go/gofrontend/README b/gcc-4.8.1/gcc/go/gofrontend/README deleted file mode 100644 index 6d4d0b0a8..000000000 --- a/gcc-4.8.1/gcc/go/gofrontend/README +++ /dev/null @@ -1,53 +0,0 @@ -See ../README. - -The frontend is written in C++. - -The frontend lexes and parses the input into an IR specific to this -frontend known as gogo. It then runs a series of passes over the -code. - -Finally it converts gogo to gcc's GENERIC. A goal is to move the gcc -support code into a gcc-interface subdirectory. The gcc code will be -put under the GPL. The rest of the frontend will not include any gcc -header files. - -Issues to be faced in this transition: - -* Representation of source locations. - + Currently the frontend uses gcc's source_location codes, using the - interface in libcpp/line-map.h. - -* Handling of error messages. - + Currently the frontend uses gcc's error_at and warning_at - functions. - + Currently the frontend uses gcc's diagnostic formatter, using - features such as %<%> for appropriate quoting. - + Localization may be an issue. - -This compiler works, but the code is a work in progress. Notably, the -support for garbage collection is ineffective and needs a complete -rethinking. The frontend pays little attention to its memory usage -and rarely frees any memory. The code could use a general cleanup -which we have not had time to do. - -Contributing -============= - -To contribute patches to the files in this directory, please see -http://golang.org/doc/gccgo_contribute.html . - -The master copy of these files is hosted at -http://code.google.com/p/gofrontend . Changes to these files require -signing a Google contributor license agreement. If you are the -copyright holder, you will need to agree to the individual contributor -license agreement at -http://code.google.com/legal/individual-cla-v1.0.html. This agreement -can be completed online. - -If your organization is the copyright holder, the organization will -need to agree to the corporate contributor license agreement at -http://code.google.com/legal/corporate-cla-v1.0.html. - -If the copyright holder for your code has already completed the -agreement in connection with another Google open source project, it -does not need to be completed again. diff --git a/gcc-4.8.1/gcc/go/gofrontend/ast-dump.cc b/gcc-4.8.1/gcc/go/gofrontend/ast-dump.cc deleted file mode 100644 index 850e31a81..000000000 --- a/gcc-4.8.1/gcc/go/gofrontend/ast-dump.cc +++ /dev/null @@ -1,469 +0,0 @@ -// ast-dump.cc -- AST debug dump. -*- C++ -*- - -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "go-system.h" - -#include <iostream> -#include <fstream> - -#include "gogo.h" -#include "expressions.h" -#include "statements.h" -#include "types.h" -#include "ast-dump.h" -#include "go-c.h" -#include "go-dump.h" - -// The -fgo-dump-ast flag to activate AST dumps. - -Go_dump ast_dump_flag("ast"); - -// This class is used to traverse the tree to look for blocks and -// function headers. - -class Ast_dump_traverse_blocks_and_functions : public Traverse -{ - public: - Ast_dump_traverse_blocks_and_functions(Ast_dump_context* ast_dump_context) - : Traverse(traverse_blocks | traverse_functions), - ast_dump_context_(ast_dump_context) - { } - - protected: - int - block(Block*); - - int - function(Named_object*); - - private: - Ast_dump_context* ast_dump_context_; -}; - -// This class is used to traverse the tree to look for statements. - -class Ast_dump_traverse_statements : public Traverse -{ - public: - Ast_dump_traverse_statements(Ast_dump_context* ast_dump_context) - : Traverse(traverse_statements), - ast_dump_context_(ast_dump_context) - { } - - protected: - int - statement(Block*, size_t* pindex, Statement*); - - private: - Ast_dump_context* ast_dump_context_; -}; - -// For each block we enclose it in brackets. - -int Ast_dump_traverse_blocks_and_functions::block(Block * block) -{ - this->ast_dump_context_->print_indent(); - this->ast_dump_context_->ostream() << "{" << std::endl; - this->ast_dump_context_->indent(); - - // Dump statememts. - Ast_dump_traverse_statements adts(this->ast_dump_context_); - block->traverse(&adts); - - this->ast_dump_context_->unindent(); - this->ast_dump_context_->print_indent(); - this->ast_dump_context_->ostream() << "}" << std::endl; - - return TRAVERSE_SKIP_COMPONENTS; -} - -// Dump each traversed statement. - -int -Ast_dump_traverse_statements::statement(Block* block, size_t* pindex, - Statement* statement) -{ - statement->dump_statement(this->ast_dump_context_); - - if (statement->is_block_statement()) - { - Ast_dump_traverse_blocks_and_functions adtbf(this->ast_dump_context_); - statement->traverse(block, pindex, &adtbf); - } - - return TRAVERSE_SKIP_COMPONENTS; -} - -// Dump the function header. - -int -Ast_dump_traverse_blocks_and_functions::function(Named_object* no) -{ - this->ast_dump_context_->ostream() << no->name(); - - go_assert(no->is_function()); - Function* func = no->func_value(); - - this->ast_dump_context_->ostream() << "("; - this->ast_dump_context_->dump_typed_identifier_list( - func->type()->parameters()); - - this->ast_dump_context_->ostream() << ")"; - - Function::Results* res = func->result_variables(); - if (res != NULL && !res->empty()) - { - this->ast_dump_context_->ostream() << " ("; - - for (Function::Results::const_iterator it = res->begin(); - it != res->end(); - it++) - { - if (it != res->begin()) - this->ast_dump_context_->ostream() << ","; - Named_object* no = (*it); - - this->ast_dump_context_->ostream() << no->name() << " "; - go_assert(no->is_result_variable()); - Result_variable* resvar = no->result_var_value(); - - this->ast_dump_context_->dump_type(resvar->type()); - - } - this->ast_dump_context_->ostream() << ")"; - } - - this->ast_dump_context_->ostream() << " : "; - this->ast_dump_context_->dump_type(func->type()); - this->ast_dump_context_->ostream() << std::endl; - - return TRAVERSE_CONTINUE; -} - -// Class Ast_dump_context. - -Ast_dump_context::Ast_dump_context(std::ostream* out /* = NULL */, - bool dump_subblocks /* = true */) - : indent_(0), dump_subblocks_(dump_subblocks), ostream_(out), gogo_(NULL) -{ -} - -// Dump files will be named %basename%.dump.ast - -const char* kAstDumpFileExtension = ".dump.ast"; - -// Dump the internal representation. - -void -Ast_dump_context::dump(Gogo* gogo, const char* basename) -{ - std::ofstream* out = new std::ofstream(); - std::string dumpname(basename); - dumpname += ".dump.ast"; - out->open(dumpname.c_str()); - - if (out->fail()) - { - error("cannot open %s:%m, -fgo-dump-ast ignored", dumpname.c_str()); - return; - } - - this->gogo_ = gogo; - this->ostream_ = out; - - Ast_dump_traverse_blocks_and_functions adtbf(this); - gogo->traverse(&adtbf); - - out->close(); -} - -// Dump a textual representation of a type to the -// the dump file. - -void -Ast_dump_context::dump_type(const Type* t) -{ - if (t == NULL) - this->ostream() << "(nil type)"; - else - // FIXME: write a type pretty printer instead of - // using mangled names. - if (this->gogo_ != NULL) - this->ostream() << "(" << t->mangled_name(this->gogo_) << ")"; -} - -// Dump a textual representation of a block to the -// the dump file. - -void -Ast_dump_context::dump_block(Block* b) -{ - Ast_dump_traverse_blocks_and_functions adtbf(this); - b->traverse(&adtbf); -} - -// Dump a textual representation of an expression to the -// the dump file. - -void -Ast_dump_context::dump_expression(const Expression* e) -{ - e->dump_expression(this); -} - -// Dump a textual representation of an expression list to the -// the dump file. - -void -Ast_dump_context::dump_expression_list(const Expression_list* el, - bool as_pairs /* = false */) -{ - if (el == NULL) - return; - - for (std::vector<Expression*>::const_iterator it = el->begin(); - it != el->end(); - it++) - { - if ( it != el->begin()) - this->ostream() << ","; - if (*it != NULL) - (*it)->dump_expression(this); - else - this->ostream() << "NULL"; - if (as_pairs) - { - this->ostream() << ":"; - ++it; - (*it)->dump_expression(this); - } - } -} - -// Dump a textual representation of a typed identifier to the -// the dump file. - -void -Ast_dump_context::dump_typed_identifier(const Typed_identifier* ti) -{ - this->ostream() << ti->name() << " "; - this->dump_type(ti->type()); -} - -// Dump a textual representation of a typed identifier list to the -// the dump file. - -void -Ast_dump_context::dump_typed_identifier_list( - const Typed_identifier_list* ti_list) -{ - if (ti_list == NULL) - return; - - for (Typed_identifier_list::const_iterator it = ti_list->begin(); - it != ti_list->end(); - it++) - { - if (it != ti_list->begin()) - this->ostream() << ","; - this->dump_typed_identifier(&(*it)); - } -} - -// Dump a textual representation of a temporary variable to the -// the dump file. - -void -Ast_dump_context::dump_temp_variable_name(const Statement* s) -{ - go_assert(s->classification() == Statement::STATEMENT_TEMPORARY); - // Use the statement address as part of the name for the temporary variable. - this->ostream() << "tmp." << (uintptr_t) s; -} - -// Dump a textual representation of a label to the -// the dump file. - -void -Ast_dump_context::dump_label_name(const Unnamed_label* l) -{ - // Use the unnamed label address as part of the name for the temporary - // variable. - this->ostream() << "label." << (uintptr_t) l; -} - -// Produce a textual representation of an operator symbol. - -static const char* -op_string(Operator op) -{ -// FIXME: This should be in line with symbols that are parsed, -// exported and/or imported. - switch (op) - { - case OPERATOR_PLUS: - return "+"; - case OPERATOR_MINUS: - return "-"; - case OPERATOR_NOT: - return "!"; - case OPERATOR_XOR: - return "^"; - case OPERATOR_OR: - return "|"; - case OPERATOR_AND: - return "&"; - case OPERATOR_MULT: - return "*"; - case OPERATOR_OROR: - return "||"; - case OPERATOR_ANDAND: - return "&&"; - case OPERATOR_EQEQ: - return "=="; - case OPERATOR_NOTEQ: - return "!="; - case OPERATOR_LT: - return "<"; - case OPERATOR_LE: - return "<="; - case OPERATOR_GT: - return ">"; - case OPERATOR_GE: - return ">="; - case OPERATOR_DIV: - return "/"; - case OPERATOR_MOD: - return "%"; - case OPERATOR_LSHIFT: - return "<<"; - case OPERATOR_RSHIFT: - return "//"; - case OPERATOR_BITCLEAR: - return "&^"; - case OPERATOR_CHANOP: - return "<-"; - case OPERATOR_PLUSEQ: - return "+="; - case OPERATOR_MINUSEQ: - return "-="; - case OPERATOR_OREQ: - return "|="; - case OPERATOR_XOREQ: - return "^="; - case OPERATOR_MULTEQ: - return "*="; - case OPERATOR_DIVEQ: - return "/="; - case OPERATOR_MODEQ: - return "%="; - case OPERATOR_LSHIFTEQ: - return "<<="; - case OPERATOR_RSHIFTEQ: - return ">>="; - case OPERATOR_ANDEQ: - return "&="; - case OPERATOR_BITCLEAREQ: - return "&^="; - case OPERATOR_PLUSPLUS: - return "++"; - case OPERATOR_MINUSMINUS: - return "--"; - case OPERATOR_COLON: - return ":"; - case OPERATOR_COLONEQ: - return ":="; - case OPERATOR_SEMICOLON: - return ";"; - case OPERATOR_DOT: - return "."; - case OPERATOR_ELLIPSIS: - return "..."; - case OPERATOR_COMMA: - return ","; - case OPERATOR_LPAREN: - return "("; - case OPERATOR_RPAREN: - return ")"; - case OPERATOR_LCURLY: - return "{"; - case OPERATOR_RCURLY: - return "}"; - case OPERATOR_LSQUARE: - return "["; - case OPERATOR_RSQUARE: - return "]"; - default: - go_unreachable(); - } - return NULL; -} - -// Dump a textual representation of an operator to the -// the dump file. - -void -Ast_dump_context::dump_operator(Operator op) -{ - this->ostream() << op_string(op); -} - -// Size of a single indent. - -const int Ast_dump_context::offset_ = 2; - -// Print indenting spaces to dump file. - -void -Ast_dump_context::print_indent() -{ - for (int i = 0; i < this->indent_ * this->offset_; i++) - this->ostream() << " "; -} - -// Dump a textual representation of the ast to the -// the dump file. - -void Gogo::dump_ast(const char* basename) -{ - if (::ast_dump_flag.is_enabled()) - { - Ast_dump_context adc; - adc.dump(this, basename); - } -} - -// Implementation of String_dump interface. - -void -Ast_dump_context::write_c_string(const char* s) -{ - this->ostream() << s; -} - -void -Ast_dump_context::write_string(const std::string& s) -{ - this->ostream() << s; -} - -// Dump statment to stream. - -void -Ast_dump_context::dump_to_stream(const Statement* stm, std::ostream* out) -{ - Ast_dump_context adc(out, false); - stm->dump_statement(&adc); -} - -// Dump expression to stream. - -void -Ast_dump_context::dump_to_stream(const Expression* expr, std::ostream* out) -{ - Ast_dump_context adc(out, false); - expr->dump_expression(&adc); -}
\ No newline at end of file diff --git a/gcc-4.8.1/gcc/go/gofrontend/ast-dump.h b/gcc-4.8.1/gcc/go/gofrontend/ast-dump.h deleted file mode 100644 index 55c93693f..000000000 --- a/gcc-4.8.1/gcc/go/gofrontend/ast-dump.h +++ /dev/null @@ -1,122 +0,0 @@ -// ast-dump.h -- AST debug dump. -*- C++ -*- - -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#ifndef GO_AST_DUMP_H -#define GO_AST_DUMP_H - -#include "string-dump.h" - -class Expression; -class Expression_list; -class Named_object; -class Statement; -class Gogo; - -// This class implements fgo-dump-ast. the -// Abstract syntax tree dump of the Go program. - -class Ast_dump_context : public String_dump -{ - public: - Ast_dump_context(std::ostream* out = NULL, bool dump_subblocks = true); - - // Initialize the dump context. - void - dump(Gogo*, const char* basename); - - // Dump spaces to dumpfile as indentation. - void - print_indent(); - - // Increase current indentation for print_indent(). - void - indent() - { ++this->indent_;} - - // Decrease current indentation for print_indent(). - void - unindent() - { --this->indent_;} - - // Whether subblocks should be dumped or not. - bool - dump_subblocks() - { return this->dump_subblocks_; } - - // Get dump output stream. - std::ostream& - ostream() - { return *this->ostream_;} - - // Dump a Block to dump file. - void - dump_block(Block*); - - // Dump a type to dump file. - void - dump_type(const Type*); - - // Dump an expression to dump file. - void - dump_expression(const Expression*); - - // Dump an expression list to dump file. - void - dump_expression_list(const Expression_list*, bool as_pairs = false); - - // Dump a typed identifier to dump file. - void - dump_typed_identifier(const Typed_identifier*); - - // Dump a typed identifier list to dump file. - void - dump_typed_identifier_list(const Typed_identifier_list*); - - // Dump temporary variable name to dump file. - void - dump_temp_variable_name(const Statement*); - - // Dump unamed lable name to dump file. - void - dump_label_name(const Unnamed_label*); - - // Dump operator symbol to dump file. - void - dump_operator(Operator); - - // Implementation of String_dump interface. - void - write_c_string(const char*); - - // Implements the String_dump interface. - void - write_string(const std::string& s); - - // Dump statement to stream. - static void - dump_to_stream(const Statement*, std::ostream*); - - // Dump expression to stream. - static void - dump_to_stream(const Expression* expr, std::ostream* out); - - private: - // Current indent level. - int indent_; - - // Indentation offset. - static const int offset_; - - // Whether subblocks of composite statements should be dumped or not. - bool dump_subblocks_; - - // Stream on output dump file. - std::ostream* ostream_; - - Gogo* gogo_; -}; - -#endif // GO_AST_DUMP_H diff --git a/gcc-4.8.1/gcc/go/gofrontend/backend.h b/gcc-4.8.1/gcc/go/gofrontend/backend.h deleted file mode 100644 index fe6db743c..000000000 --- a/gcc-4.8.1/gcc/go/gofrontend/backend.h +++ /dev/null @@ -1,479 +0,0 @@ -// backend.h -- Go frontend interface to backend -*- C++ -*- - -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#ifndef GO_BACKEND_H -#define GO_BACKEND_H - -// Pointers to these types are created by the backend, passed to the -// frontend, and passed back to the backend. The types must be -// defined by the backend using these names. - -// The backend representation of a type. -class Btype; - -// The backend represention of an expression. -class Bexpression; - -// The backend representation of a statement. -class Bstatement; - -// The backend representation of a function definition. -class Bfunction; - -// The backend representation of a block. -class Bblock; - -// The backend representation of a variable. -class Bvariable; - -// The backend representation of a label. -class Blabel; - -// The backend interface. This is a pure abstract class that a -// specific backend will implement. - -class Backend -{ - public: - virtual ~Backend() { } - - // Name/type/location. Used for function parameters, struct fields, - // interface methods. - struct Btyped_identifier - { - std::string name; - Btype* btype; - Location location; - - Btyped_identifier() - : name(), btype(NULL), location(UNKNOWN_LOCATION) - { } - - Btyped_identifier(const std::string& a_name, Btype* a_btype, - Location a_location) - : name(a_name), btype(a_btype), location(a_location) - { } - }; - - // Types. - - // Produce an error type. Actually the backend could probably just - // crash if this is called. - virtual Btype* - error_type() = 0; - - // Get a void type. This is used in (at least) two ways: 1) as the - // return type of a function with no result parameters; 2) - // unsafe.Pointer is represented as *void. - virtual Btype* - void_type() = 0; - - // Get the unnamed boolean type. - virtual Btype* - bool_type() = 0; - - // Get an unnamed integer type with the given signedness and number - // of bits. - virtual Btype* - integer_type(bool is_unsigned, int bits) = 0; - - // Get an unnamed floating point type with the given number of bits - // (32 or 64). - virtual Btype* - float_type(int bits) = 0; - - // Get an unnamed complex type with the given number of bits (64 or 128). - virtual Btype* - complex_type(int bits) = 0; - - // Get a pointer type. - virtual Btype* - pointer_type(Btype* to_type) = 0; - - // Get a function type. The receiver, parameter, and results are - // generated from the types in the Function_type. The Function_type - // is provided so that the names are available. - virtual Btype* - function_type(const Btyped_identifier& receiver, - const std::vector<Btyped_identifier>& parameters, - const std::vector<Btyped_identifier>& results, - Location location) = 0; - - // Get a struct type. - virtual Btype* - struct_type(const std::vector<Btyped_identifier>& fields) = 0; - - // Get an array type. - virtual Btype* - array_type(Btype* element_type, Bexpression* length) = 0; - - // Create a placeholder pointer type. This is used for a named - // pointer type, since in Go a pointer type may refer to itself. - // NAME is the name of the type, and the location is where the named - // type is defined. This function is also used for unnamed function - // types with multiple results, in which case the type has no name - // and NAME will be empty. FOR_FUNCTION is true if this is for a Go - // function type, which corresponds to a C/C++ pointer to function - // type. The return value will later be passed as the first - // parameter to set_placeholder_pointer_type or - // set_placeholder_function_type. - virtual Btype* - placeholder_pointer_type(const std::string& name, Location, - bool for_function) = 0; - - // Fill in a placeholder pointer type as a pointer. This takes a - // type returned by placeholder_pointer_type and arranges for it to - // point to the type that TO_TYPE points to (that is, PLACEHOLDER - // becomes the same type as TO_TYPE). Returns true on success, - // false on failure. - virtual bool - set_placeholder_pointer_type(Btype* placeholder, Btype* to_type) = 0; - - // Fill in a placeholder pointer type as a function. This takes a - // type returned by placeholder_pointer_type and arranges for it to - // become a real Go function type (which corresponds to a C/C++ - // pointer to function type). FT will be something returned by the - // function_type method. Returns true on success, false on failure. - virtual bool - set_placeholder_function_type(Btype* placeholder, Btype* ft) = 0; - - // Create a placeholder struct type. This is used for a named - // struct type, as with placeholder_pointer_type. It is also used - // for interface types, in which case NAME will be the empty string. - virtual Btype* - placeholder_struct_type(const std::string& name, Location) = 0; - - // Fill in a placeholder struct type. This takes a type returned by - // placeholder_struct_type and arranges for it to become a real - // struct type. The parameter is as for struct_type. Returns true - // on success, false on failure. - virtual bool - set_placeholder_struct_type(Btype* placeholder, - const std::vector<Btyped_identifier>& fields) - = 0; - - // Create a placeholder array type. This is used for a named array - // type, as with placeholder_pointer_type, to handle cases like - // type A []*A. - virtual Btype* - placeholder_array_type(const std::string& name, Location) = 0; - - // Fill in a placeholder array type. This takes a type returned by - // placeholder_array_type and arranges for it to become a real array - // type. The parameters are as for array_type. Returns true on - // success, false on failure. - virtual bool - set_placeholder_array_type(Btype* placeholder, Btype* element_type, - Bexpression* length) = 0; - - // Return a named version of a type. The location is the location - // of the type definition. This will not be called for a type - // created via placeholder_pointer_type, placeholder_struct_type, or - // placeholder_array_type.. (It may be called for a pointer, - // struct, or array type in a case like "type P *byte; type Q P".) - virtual Btype* - named_type(const std::string& name, Btype*, Location) = 0; - - // Create a marker for a circular pointer type. Go pointer and - // function types can refer to themselves in ways that are not - // permitted in C/C++. When a circular type is found, this function - // is called for the circular reference. This permits the backend - // to decide how to handle such a type. PLACEHOLDER is the - // placeholder type which has already been created; if the backend - // is prepared to handle a circular pointer type, it may simply - // return PLACEHOLDER. FOR_FUNCTION is true if this is for a - // function type. - // - // For "type P *P" the sequence of calls will be - // bt1 = placeholder_pointer_type(); - // bt2 = circular_pointer_type(bt1, false); - // set_placeholder_pointer_type(bt1, bt2); - virtual Btype* - circular_pointer_type(Btype* placeholder, bool for_function) = 0; - - // Return whether the argument could be a special type created by - // circular_pointer_type. This is used to introduce explicit type - // conversions where needed. If circular_pointer_type returns its - // PLACEHOLDER parameter, this may safely always return false. - virtual bool - is_circular_pointer_type(Btype*) = 0; - - // Return the size of a type. - virtual size_t - type_size(Btype*) = 0; - - // Return the alignment of a type. - virtual size_t - type_alignment(Btype*) = 0; - - // Return the alignment of a struct field of this type. This is - // normally the same as type_alignment, but not always. - virtual size_t - type_field_alignment(Btype*) = 0; - - // Return the offset of field INDEX in a struct type. INDEX is the - // entry in the FIELDS std::vector parameter of struct_type or - // set_placeholder_struct_type. - virtual size_t - type_field_offset(Btype*, size_t index) = 0; - - // Expressions. - - // Return an expression for a zero value of the given type. This is - // used for cases such as local variable initialization and - // converting nil to other types. - virtual Bexpression* - zero_expression(Btype*) = 0; - - // Statements. - - // Create an error statement. This is used for cases which should - // not occur in a correct program, in order to keep the compilation - // going without crashing. - virtual Bstatement* - error_statement() = 0; - - // Create an expression statement. - virtual Bstatement* - expression_statement(Bexpression*) = 0; - - // Create a variable initialization statement. This initializes a - // local variable at the point in the program flow where it is - // declared. - virtual Bstatement* - init_statement(Bvariable* var, Bexpression* init) = 0; - - // Create an assignment statement. - virtual Bstatement* - assignment_statement(Bexpression* lhs, Bexpression* rhs, - Location) = 0; - - // Create a return statement, passing the representation of the - // function and the list of values to return. - virtual Bstatement* - return_statement(Bfunction*, const std::vector<Bexpression*>&, - Location) = 0; - - // Create an if statement. ELSE_BLOCK may be NULL. - virtual Bstatement* - if_statement(Bexpression* condition, Bblock* then_block, Bblock* else_block, - Location) = 0; - - // Create a switch statement where the case values are constants. - // CASES and STATEMENTS must have the same number of entries. If - // VALUE matches any of the list in CASES[i], which will all be - // integers, then STATEMENTS[i] is executed. STATEMENTS[i] will - // either end with a goto statement or will fall through into - // STATEMENTS[i + 1]. CASES[i] is empty for the default clause, - // which need not be last. - virtual Bstatement* - switch_statement(Bexpression* value, - const std::vector<std::vector<Bexpression*> >& cases, - const std::vector<Bstatement*>& statements, - Location) = 0; - - // Create a single statement from two statements. - virtual Bstatement* - compound_statement(Bstatement*, Bstatement*) = 0; - - // Create a single statement from a list of statements. - virtual Bstatement* - statement_list(const std::vector<Bstatement*>&) = 0; - - // Blocks. - - // Create a block. The frontend will call this function when it - // starts converting a block within a function. FUNCTION is the - // current function. ENCLOSING is the enclosing block; it will be - // NULL for the top-level block in a function. VARS is the list of - // local variables defined within this block; each entry will be - // created by the local_variable function. START_LOCATION is the - // location of the start of the block, more or less the location of - // the initial curly brace. END_LOCATION is the location of the end - // of the block, more or less the location of the final curly brace. - // The statements will be added after the block is created. - virtual Bblock* - block(Bfunction* function, Bblock* enclosing, - const std::vector<Bvariable*>& vars, - Location start_location, Location end_location) = 0; - - // Add the statements to a block. The block is created first. Then - // the statements are created. Then the statements are added to the - // block. This will called exactly once per block. The vector may - // be empty if there are no statements. - virtual void - block_add_statements(Bblock*, const std::vector<Bstatement*>&) = 0; - - // Return the block as a statement. This is used to include a block - // in a list of statements. - virtual Bstatement* - block_statement(Bblock*) = 0; - - // Variables. - - // Create an error variable. This is used for cases which should - // not occur in a correct program, in order to keep the compilation - // going without crashing. - virtual Bvariable* - error_variable() = 0; - - // Create a global variable. PACKAGE_NAME is the name of the - // package where the variable is defined. PKGPATH is the package - // path for that package, from the -fgo-pkgpath or -fgo-prefix - // option. NAME is the name of the variable. BTYPE is the type of - // the variable. IS_EXTERNAL is true if the variable is defined in - // some other package. IS_HIDDEN is true if the variable is not - // exported (name begins with a lower case letter). - // IN_UNIQUE_SECTION is true if the variable should be put into a - // unique section if possible; this is intended to permit the linker - // to garbage collect the variable if it is not referenced. - // LOCATION is where the variable was defined. - virtual Bvariable* - global_variable(const std::string& package_name, - const std::string& pkgpath, - const std::string& name, - Btype* btype, - bool is_external, - bool is_hidden, - bool in_unique_section, - Location location) = 0; - - // A global variable will 1) be initialized to zero, or 2) be - // initialized to a constant value, or 3) be initialized in the init - // function. In case 2, the frontend will call - // global_variable_set_init to set the initial value. If this is - // not called, the backend should initialize a global variable to 0. - // The init function may then assign a value to it. - virtual void - global_variable_set_init(Bvariable*, Bexpression*) = 0; - - // Create a local variable. The frontend will create the local - // variables first, and then create the block which contains them. - // FUNCTION is the function in which the variable is defined. NAME - // is the name of the variable. TYPE is the type. IS_ADDRESS_TAKEN - // is true if the address of this variable is taken (this implies - // that the address does not escape the function, as otherwise the - // variable would be on the heap). LOCATION is where the variable - // is defined. For each local variable the frontend will call - // init_statement to set the initial value. - virtual Bvariable* - local_variable(Bfunction* function, const std::string& name, Btype* type, - bool is_address_taken, Location location) = 0; - - // Create a function parameter. This is an incoming parameter, not - // a result parameter (result parameters are treated as local - // variables). The arguments are as for local_variable. - virtual Bvariable* - parameter_variable(Bfunction* function, const std::string& name, - Btype* type, bool is_address_taken, - Location location) = 0; - - // Create a temporary variable. A temporary variable has no name, - // just a type. We pass in FUNCTION and BLOCK in case they are - // needed. If INIT is not NULL, the variable should be initialized - // to that value. Otherwise the initial value is irrelevant--the - // backend does not have to explicitly initialize it to zero. - // ADDRESS_IS_TAKEN is true if the programs needs to take the - // address of this temporary variable. LOCATION is the location of - // the statement or expression which requires creating the temporary - // variable, and may not be very useful. This function should - // return a variable which can be referenced later and should set - // *PSTATEMENT to a statement which initializes the variable. - virtual Bvariable* - temporary_variable(Bfunction*, Bblock*, Btype*, Bexpression* init, - bool address_is_taken, Location location, - Bstatement** pstatement) = 0; - - // Create a named immutable initialized data structure. This is - // used for type descriptors and map descriptors. This returns a - // Bvariable because it corresponds to an initialized const global - // variable in C. - // - // NAME is the name to use for the initialized global variable which - // this call will create. - // - // IS_COMMON is true if NAME may be defined by several packages, and - // the linker should merge all such definitions. If IS_COMMON is - // false, NAME should be defined in only one file. In general - // IS_COMMON will be true for the type descriptor of an unnamed type - // or a builtin type. - // - // TYPE will be a struct type; the type of the returned expression - // must be a pointer to this struct type. - // - // We must create the named structure before we know its - // initializer, because the initializer may refer to its own - // address. After calling this the frontend will call - // immutable_struct_set_init. - virtual Bvariable* - immutable_struct(const std::string& name, bool is_common, Btype* type, - Location) = 0; - - // Set the initial value of a variable created by immutable_struct. - // The NAME, IS_COMMON, TYPE, and location parameters are the same - // ones passed to immutable_struct. INITIALIZER will be a composite - // literal of type TYPE. It will not contain any function calls or - // anything else which can not be put into a read-only data section. - // It may contain the address of variables created by - // immutable_struct. - virtual void - immutable_struct_set_init(Bvariable*, const std::string& name, - bool is_common, Btype* type, Location, - Bexpression* initializer) = 0; - - // Create a reference to a named immutable initialized data - // structure defined in some other package. This will be a - // structure created by a call to immutable_struct with the same - // NAME and TYPE and with IS_COMMON passed as false. This - // corresponds to an extern const global variable in C. - virtual Bvariable* - immutable_struct_reference(const std::string& name, Btype* type, - Location) = 0; - - // Labels. - - // Create a new label. NAME will be empty if this is a label - // created by the frontend for a loop construct. The location is - // where the the label is defined. - virtual Blabel* - label(Bfunction*, const std::string& name, Location) = 0; - - // Create a statement which defines a label. This statement will be - // put into the codestream at the point where the label should be - // defined. - virtual Bstatement* - label_definition_statement(Blabel*) = 0; - - // Create a goto statement to a label. - virtual Bstatement* - goto_statement(Blabel*, Location) = 0; - - // Create an expression for the address of a label. This is used to - // get the return address of a deferred function which may call - // recover. - virtual Bexpression* - label_address(Blabel*, Location) = 0; -}; - -// The backend interface has to define this function. - -extern Backend* go_get_backend(); - -// FIXME: Temporary helper functions while converting to new backend -// interface. - -extern Btype* tree_to_type(tree); -extern Bexpression* tree_to_expr(tree); -extern Bstatement* tree_to_stat(tree); -extern Bfunction* tree_to_function(tree); -extern Bblock* tree_to_block(tree); -extern tree type_to_tree(Btype*); -extern tree expr_to_tree(Bexpression*); -extern tree stat_to_tree(Bstatement*); -extern tree block_to_tree(Bblock*); -extern tree var_to_tree(Bvariable*); - -#endif // !defined(GO_BACKEND_H) diff --git a/gcc-4.8.1/gcc/go/gofrontend/dataflow.cc b/gcc-4.8.1/gcc/go/gofrontend/dataflow.cc deleted file mode 100644 index 572ab3631..000000000 --- a/gcc-4.8.1/gcc/go/gofrontend/dataflow.cc +++ /dev/null @@ -1,278 +0,0 @@ -// dataflow.cc -- Go frontend dataflow. - -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "go-system.h" - -#include "gogo.h" -#include "expressions.h" -#include "statements.h" -#include "dataflow.h" - -// This class is used to traverse the tree to look for uses of -// variables. - -class Dataflow_traverse_expressions : public Traverse -{ - public: - Dataflow_traverse_expressions(Dataflow* dataflow, Statement* statement) - : Traverse(traverse_blocks | traverse_expressions), - dataflow_(dataflow), statement_(statement) - { } - - protected: - // Only look at top-level expressions: do not descend into blocks. - // They will be examined via Dataflow_traverse_statements. - int - block(Block*) - { return TRAVERSE_SKIP_COMPONENTS; } - - int - expression(Expression**); - - private: - // The dataflow information. - Dataflow* dataflow_; - // The Statement in which we are looking. - Statement* statement_; -}; - -// Given an expression, return the Named_object that it refers to, if -// it is a local variable. - -static Named_object* -get_var(Expression* expr) -{ - Var_expression* ve = expr->var_expression(); - if (ve == NULL) - return NULL; - Named_object* no = ve->named_object(); - go_assert(no->is_variable() || no->is_result_variable()); - if (no->is_variable() && no->var_value()->is_global()) - return NULL; - return no; -} - -// Look for a reference to a variable in an expression. - -int -Dataflow_traverse_expressions::expression(Expression** expr) -{ - Named_object* no = get_var(*expr); - if (no != NULL) - this->dataflow_->add_ref(no, this->statement_); - return TRAVERSE_CONTINUE; -} - -// This class is used to handle an assignment statement. - -class Dataflow_traverse_assignment : public Traverse_assignments -{ - public: - Dataflow_traverse_assignment(Dataflow* dataflow, Statement* statement) - : dataflow_(dataflow), statement_(statement) - { } - - protected: - void - initialize_variable(Named_object*); - - void - assignment(Expression** lhs, Expression** rhs); - - void - value(Expression**, bool, bool); - - private: - // The dataflow information. - Dataflow* dataflow_; - // The Statement in which we are looking. - Statement* statement_; -}; - -// Handle a variable initialization. - -void -Dataflow_traverse_assignment::initialize_variable(Named_object* var) -{ - Expression* init = var->var_value()->init(); - this->dataflow_->add_def(var, init, this->statement_, true); - if (init != NULL) - { - Expression* e = init; - this->value(&e, true, true); - go_assert(e == init); - } -} - -// Handle an assignment in a statement. - -void -Dataflow_traverse_assignment::assignment(Expression** plhs, Expression** prhs) -{ - Named_object* no = get_var(*plhs); - if (no != NULL) - { - Expression* rhs = prhs == NULL ? NULL : *prhs; - this->dataflow_->add_def(no, rhs, this->statement_, false); - } - else - { - // If this is not a variable it may be some computed lvalue, and - // we want to look for references to variables in that lvalue. - this->value(plhs, false, false); - } - if (prhs != NULL) - this->value(prhs, true, false); -} - -// Handle a value in a statement. - -void -Dataflow_traverse_assignment::value(Expression** pexpr, bool, bool) -{ - Named_object* no = get_var(*pexpr); - if (no != NULL) - this->dataflow_->add_ref(no, this->statement_); - else - { - Dataflow_traverse_expressions dte(this->dataflow_, this->statement_); - Expression::traverse(pexpr, &dte); - } -} - -// This class is used to traverse the tree to look for statements. - -class Dataflow_traverse_statements : public Traverse -{ - public: - Dataflow_traverse_statements(Dataflow* dataflow) - : Traverse(traverse_statements), - dataflow_(dataflow) - { } - - protected: - int - statement(Block*, size_t* pindex, Statement*); - - private: - // The dataflow information. - Dataflow* dataflow_; -}; - -// For each Statement, we look for expressions. - -int -Dataflow_traverse_statements::statement(Block* block, size_t* pindex, - Statement *statement) -{ - Dataflow_traverse_assignment dta(this->dataflow_, statement); - if (!statement->traverse_assignments(&dta)) - { - Dataflow_traverse_expressions dte(this->dataflow_, statement); - statement->traverse(block, pindex, &dte); - } - return TRAVERSE_CONTINUE; -} - -// Compare variables. - -bool -Dataflow::Compare_vars::operator()(const Named_object* no1, - const Named_object* no2) const -{ - if (no1->name() < no2->name()) - return true; - if (no1->name() > no2->name()) - return false; - - // We can have two different variables with the same name. - Location loc1 = no1->location(); - Location loc2 = no2->location(); - if (loc1 < loc2) - return false; - if (loc1 > loc2) - return true; - - if (no1 == no2) - return false; - - // We can't have two variables with the same name in the same - // location. - go_unreachable(); -} - -// Class Dataflow. - -Dataflow::Dataflow() - : defs_(), refs_() -{ -} - -// Build the dataflow information. - -void -Dataflow::initialize(Gogo* gogo) -{ - Dataflow_traverse_statements dts(this); - gogo->traverse(&dts); -} - -// Add a definition of a variable. - -void -Dataflow::add_def(Named_object* var, Expression* val, Statement* statement, - bool is_init) -{ - Defs* defnull = NULL; - std::pair<Defmap::iterator, bool> ins = - this->defs_.insert(std::make_pair(var, defnull)); - if (ins.second) - ins.first->second = new Defs; - Def def; - def.statement = statement; - def.val = val; - def.is_init = is_init; - ins.first->second->push_back(def); -} - -// Add a reference to a variable. - -void -Dataflow::add_ref(Named_object* var, Statement* statement) -{ - Refs* refnull = NULL; - std::pair<Refmap::iterator, bool> ins = - this->refs_.insert(std::make_pair(var, refnull)); - if (ins.second) - ins.first->second = new Refs; - Ref ref; - ref.statement = statement; - ins.first->second->push_back(ref); -} - -// Return the definitions of a variable. - -const Dataflow::Defs* -Dataflow::find_defs(Named_object* var) const -{ - Defmap::const_iterator p = this->defs_.find(var); - if (p == this->defs_.end()) - return NULL; - else - return p->second; -} - -// Return the references of a variable. - -const Dataflow::Refs* -Dataflow::find_refs(Named_object* var) const -{ - Refmap::const_iterator p = this->refs_.find(var); - if (p == this->refs_.end()) - return NULL; - else - return p->second; -} diff --git a/gcc-4.8.1/gcc/go/gofrontend/dataflow.h b/gcc-4.8.1/gcc/go/gofrontend/dataflow.h deleted file mode 100644 index a75c8e661..000000000 --- a/gcc-4.8.1/gcc/go/gofrontend/dataflow.h +++ /dev/null @@ -1,91 +0,0 @@ -// dataflow.h -- Go frontend dataflow. -*- C++ -*- - -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#ifndef GO_DATAFLOW_H -#define GO_DATAFLOW_H - -class Expression; -class Named_object; -class Statement; - -// Dataflow information about the Go program. - -class Dataflow -{ - public: - // A variable definition. - struct Def - { - // The statement where the variable is defined. - Statement* statement; - // The value to which the variable is set. This may be NULL. - Expression* val; - // Whether this is an initialization of the variable. - bool is_init; - }; - - // A variable reference. - struct Ref - { - // The statement where the variable is referenced. - Statement* statement; - }; - - // A list of defs. - typedef std::vector<Def> Defs; - - // A list of refs. - typedef std::vector<Ref> Refs; - - Dataflow(); - - // Initialize the dataflow information. - void - initialize(Gogo*); - - // Add a definition of a variable. STATEMENT assigns a value to - // VAR. VAL is the value if it is known, NULL otherwise. - void - add_def(Named_object* var, Expression* val, Statement* statement, - bool is_init); - - // Add a reference to a variable. VAR is the variable, and - // STATEMENT is the statement which refers to it. - void - add_ref(Named_object* var, Statement* statement); - - // Return the definitions of VAR--the places where it is set. - const Defs* - find_defs(Named_object* var) const; - - // Return the references to VAR--the places where it is used. - const Refs* - find_refs(Named_object* var) const; - - private: - // Order variables in the map. - struct Compare_vars - { - bool - operator()(const Named_object*, const Named_object*) const; - }; - - // Map from variables to a list of defs of the variable. We use a - // map rather than a hash table because the order in which we - // process variables may affect the resulting code. - typedef std::map<Named_object*, Defs*, Compare_vars> Defmap; - - // Map from variables to a list of refs to the vairable. - typedef std::map<Named_object*, Refs*, Compare_vars> Refmap; - - // Variable defs. - Defmap defs_; - // Variable refs; - Refmap refs_; -}; - - -#endif // !defined(GO_DATAFLOW_H) diff --git a/gcc-4.8.1/gcc/go/gofrontend/export.cc b/gcc-4.8.1/gcc/go/gofrontend/export.cc deleted file mode 100644 index 13c61a589..000000000 --- a/gcc-4.8.1/gcc/go/gofrontend/export.cc +++ /dev/null @@ -1,491 +0,0 @@ -// export.cc -- Export declarations in Go frontend. - -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "go-system.h" - -#include "sha1.h" - -#include "go-c.h" - -#include "gogo.h" -#include "types.h" -#include "statements.h" -#include "export.h" - -// This file handles exporting global declarations. - -// Class Export. - -// Version 1 magic number. - -const int Export::v1_magic_len; - -const char Export::v1_magic[Export::v1_magic_len] = - { - 'v', '1', ';', '\n' - }; - -const int Export::v1_checksum_len; - -// Constructor. - -Export::Export(Stream* stream) - : stream_(stream), type_refs_(), type_index_(1), packages_() -{ -} - -// A functor to sort Named_object pointers by name. - -struct Sort_bindings -{ - bool - operator()(const Named_object* n1, const Named_object* n2) const - { return n1->name() < n2->name(); } -}; - -// Return true if we should export NO. - -static bool -should_export(Named_object* no) -{ - // We only export objects which are locally defined. - if (no->package() != NULL) - return false; - - // We don't export packages. - if (no->is_package()) - return false; - - // We don't export hidden names. - if (Gogo::is_hidden_name(no->name())) - return false; - - // We don't export nested functions. - if (no->is_function() && no->func_value()->enclosing() != NULL) - return false; - - // We don't export thunks. - if (no->is_function() && Gogo::is_thunk(no)) - return false; - - // Methods are exported with the type, not here. - if (no->is_function() - && no->func_value()->type()->is_method()) - return false; - if (no->is_function_declaration() - && no->func_declaration_value()->type()->is_method()) - return false; - - // Don't export dummy global variables created for initializers when - // used with sinks. - if (no->is_variable() && no->name()[0] == '_' && no->name()[1] == '.') - return false; - - return true; -} - -// Export those identifiers marked for exporting. - -void -Export::export_globals(const std::string& package_name, - const std::string& pkgpath, - int package_priority, - const std::map<std::string, Package*>& imports, - const std::string& import_init_fn, - const std::set<Import_init>& imported_init_fns, - const Bindings* bindings) -{ - // If there have been any errors so far, don't try to export - // anything. That way the export code doesn't have to worry about - // mismatched types or other confusions. - if (saw_errors()) - return; - - // Export the symbols in sorted order. That will reduce cases where - // irrelevant changes to the source code affect the exported - // interface. - std::vector<Named_object*> exports; - exports.reserve(bindings->size_definitions()); - - for (Bindings::const_definitions_iterator p = bindings->begin_definitions(); - p != bindings->end_definitions(); - ++p) - if (should_export(*p)) - exports.push_back(*p); - - for (Bindings::const_declarations_iterator p = - bindings->begin_declarations(); - p != bindings->end_declarations(); - ++p) - { - // We export a function declaration as it may be implemented in - // supporting C code. We do not export type declarations. - if (p->second->is_function_declaration() - && should_export(p->second)) - exports.push_back(p->second); - } - - std::sort(exports.begin(), exports.end(), Sort_bindings()); - - // Although the export data is readable, at least this version is, - // it is conceptually a binary format. Start with a four byte - // verison number. - this->write_bytes(Export::v1_magic, Export::v1_magic_len); - - // The package name. - this->write_c_string("package "); - this->write_string(package_name); - this->write_c_string(";\n"); - - // The package path, used for all global symbols. - this->write_c_string("pkgpath "); - this->write_string(pkgpath); - this->write_c_string(";\n"); - - // The package priority. - char buf[100]; - snprintf(buf, sizeof buf, "priority %d;\n", package_priority); - this->write_c_string(buf); - - this->write_imports(imports); - - this->write_imported_init_fns(package_name, package_priority, import_init_fn, - imported_init_fns); - - // FIXME: It might be clever to add something about the processor - // and ABI being used, although ideally any problems in that area - // would be caught by the linker. - - for (std::vector<Named_object*>::const_iterator p = exports.begin(); - p != exports.end(); - ++p) - (*p)->export_named_object(this); - - std::string checksum = this->stream_->checksum(); - std::string s = "checksum "; - for (std::string::const_iterator p = checksum.begin(); - p != checksum.end(); - ++p) - { - unsigned char c = *p; - unsigned int dig = c >> 4; - s += dig < 10 ? '0' + dig : 'A' + dig - 10; - dig = c & 0xf; - s += dig < 10 ? '0' + dig : 'A' + dig - 10; - } - s += ";\n"; - this->stream_->write_checksum(s); -} - -// Sort imported packages. - -static bool -import_compare(const std::pair<std::string, Package*>& a, - const std::pair<std::string, Package*>& b) -{ - return a.first < b.first; -} - -// Write out the imported packages. - -void -Export::write_imports(const std::map<std::string, Package*>& imports) -{ - // Sort the imports for more consistent output. - std::vector<std::pair<std::string, Package*> > imp; - for (std::map<std::string, Package*>::const_iterator p = imports.begin(); - p != imports.end(); - ++p) - imp.push_back(std::make_pair(p->first, p->second)); - - std::sort(imp.begin(), imp.end(), import_compare); - - for (std::vector<std::pair<std::string, Package*> >::const_iterator p = - imp.begin(); - p != imp.end(); - ++p) - { - this->write_c_string("import "); - this->write_string(p->second->package_name()); - this->write_c_string(" "); - this->write_string(p->second->pkgpath()); - this->write_c_string(" \""); - this->write_string(p->first); - this->write_c_string("\";\n"); - - this->packages_.insert(p->second); - } -} - -// Write out the initialization functions which need to run for this -// package. - -void -Export::write_imported_init_fns( - const std::string& package_name, - int priority, - const std::string& import_init_fn, - const std::set<Import_init>& imported_init_fns) -{ - if (import_init_fn.empty() && imported_init_fns.empty()) - return; - - this->write_c_string("init"); - - if (!import_init_fn.empty()) - { - this->write_c_string(" "); - this->write_string(package_name); - this->write_c_string(" "); - this->write_string(import_init_fn); - char buf[100]; - snprintf(buf, sizeof buf, " %d", priority); - this->write_c_string(buf); - } - - if (!imported_init_fns.empty()) - { - // Sort the list of functions for more consistent output. - std::vector<Import_init> v; - for (std::set<Import_init>::const_iterator p = imported_init_fns.begin(); - p != imported_init_fns.end(); - ++p) - v.push_back(*p); - std::sort(v.begin(), v.end()); - - for (std::vector<Import_init>::const_iterator p = v.begin(); - p != v.end(); - ++p) - { - this->write_c_string(" "); - this->write_string(p->package_name()); - this->write_c_string(" "); - this->write_string(p->init_name()); - char buf[100]; - snprintf(buf, sizeof buf, " %d", p->priority()); - this->write_c_string(buf); - } - } - - this->write_c_string(";\n"); -} - -// Write a name to the export stream. - -void -Export::write_name(const std::string& name) -{ - if (name.empty()) - this->write_c_string("?"); - else - this->write_string(Gogo::message_name(name)); -} - -// Export a type. We have to ensure that on import we create a single -// Named_type node for each named type. We do this by keeping a hash -// table mapping named types to reference numbers. The first time we -// see a named type we assign it a reference number by making an entry -// in the hash table. If we see it again, we just refer to the -// reference number. - -// Named types are, of course, associated with packages. Note that we -// may see a named type when importing one package, and then later see -// the same named type when importing a different package. The home -// package may or may not be imported during this compilation. The -// reference number scheme has to get this all right. Basic approach -// taken from "On the Linearization of Graphs and Writing Symbol -// Files" by Robert Griesemer. - -void -Export::write_type(const Type* type) -{ - // We don't want to assign a reference number to a forward - // declaration to a type which was defined later. - type = type->forwarded(); - - Type_refs::const_iterator p = this->type_refs_.find(type); - if (p != this->type_refs_.end()) - { - // This type was already in the table. - int index = p->second; - go_assert(index != 0); - char buf[30]; - snprintf(buf, sizeof buf, "<type %d>", index); - this->write_c_string(buf); - return; - } - - const Named_type* named_type = type->named_type(); - const Forward_declaration_type* forward = type->forward_declaration_type(); - - int index = this->type_index_; - ++this->type_index_; - - char buf[30]; - snprintf(buf, sizeof buf, "<type %d ", index); - this->write_c_string(buf); - - if (named_type != NULL || forward != NULL) - { - const Named_object* named_object; - if (named_type != NULL) - { - // The builtin types should have been predefined. - go_assert(!Linemap::is_predeclared_location(named_type->location()) - || (named_type->named_object()->package()->package_name() - == "unsafe")); - named_object = named_type->named_object(); - } - else - named_object = forward->named_object(); - - const Package* package = named_object->package(); - - std::string s = "\""; - if (package != NULL && !Gogo::is_hidden_name(named_object->name())) - { - s += package->pkgpath(); - s += '.'; - } - s += named_object->name(); - s += "\" "; - this->write_string(s); - - // It is possible that this type was imported indirectly, and is - // not in a package in the import list. If we have not - // mentioned this package before, write out the package name - // here so that any package importing this one will know it. - if (package != NULL - && this->packages_.find(package) == this->packages_.end()) - { - this->write_c_string("\""); - this->write_string(package->package_name()); - this->packages_.insert(package); - this->write_c_string("\" "); - } - - // We must add a named type to the table now, since the - // definition of the type may refer to the named type via a - // pointer. - this->type_refs_[type] = index; - } - - type->export_type(this); - - this->write_c_string(">"); - - if (named_type == NULL) - this->type_refs_[type] = index; -} - -// Add the builtin types to the export table. - -void -Export::register_builtin_types(Gogo* gogo) -{ - this->register_builtin_type(gogo, "int8", BUILTIN_INT8); - this->register_builtin_type(gogo, "int16", BUILTIN_INT16); - this->register_builtin_type(gogo, "int32", BUILTIN_INT32); - this->register_builtin_type(gogo, "int64", BUILTIN_INT64); - this->register_builtin_type(gogo, "uint8", BUILTIN_UINT8); - this->register_builtin_type(gogo, "uint16", BUILTIN_UINT16); - this->register_builtin_type(gogo, "uint32", BUILTIN_UINT32); - this->register_builtin_type(gogo, "uint64", BUILTIN_UINT64); - this->register_builtin_type(gogo, "float32", BUILTIN_FLOAT32); - this->register_builtin_type(gogo, "float64", BUILTIN_FLOAT64); - this->register_builtin_type(gogo, "complex64", BUILTIN_COMPLEX64); - this->register_builtin_type(gogo, "complex128", BUILTIN_COMPLEX128); - this->register_builtin_type(gogo, "int", BUILTIN_INT); - this->register_builtin_type(gogo, "uint", BUILTIN_UINT); - this->register_builtin_type(gogo, "uintptr", BUILTIN_UINTPTR); - this->register_builtin_type(gogo, "bool", BUILTIN_BOOL); - this->register_builtin_type(gogo, "string", BUILTIN_STRING); - this->register_builtin_type(gogo, "error", BUILTIN_ERROR); - this->register_builtin_type(gogo, "byte", BUILTIN_BYTE); - this->register_builtin_type(gogo, "rune", BUILTIN_RUNE); -} - -// Register one builtin type in the export table. - -void -Export::register_builtin_type(Gogo* gogo, const char* name, Builtin_code code) -{ - Named_object* named_object = gogo->lookup_global(name); - go_assert(named_object != NULL && named_object->is_type()); - std::pair<Type_refs::iterator, bool> ins = - this->type_refs_.insert(std::make_pair(named_object->type_value(), code)); - go_assert(ins.second); - - // We also insert the underlying type. We can see the underlying - // type at least for string and bool. We skip the type aliases byte - // and rune here. - if (code != BUILTIN_BYTE && code != BUILTIN_RUNE) - { - Type* real_type = named_object->type_value()->real_type(); - ins = this->type_refs_.insert(std::make_pair(real_type, code)); - go_assert(ins.second); - } -} - -// Class Export::Stream. - -Export::Stream::Stream() -{ - this->checksum_ = new sha1_ctx; - memset(this->checksum_, 0, sizeof(sha1_ctx)); - sha1_init_ctx(this->checksum_); -} - -Export::Stream::~Stream() -{ -} - -// Write bytes to the stream. This keeps a checksum of bytes as they -// go by. - -void -Export::Stream::write_and_sum_bytes(const char* bytes, size_t length) -{ - sha1_process_bytes(bytes, length, this->checksum_); - this->do_write(bytes, length); -} - -// Get the checksum. - -std::string -Export::Stream::checksum() -{ - // Use a union to provide the required alignment. - union - { - char checksum[Export::v1_checksum_len]; - long align; - } u; - sha1_finish_ctx(this->checksum_, u.checksum); - return std::string(u.checksum, Export::v1_checksum_len); -} - -// Write the checksum string to the export data. - -void -Export::Stream::write_checksum(const std::string& s) -{ - this->do_write(s.data(), s.length()); -} - -// Class Stream_to_section. - -Stream_to_section::Stream_to_section() -{ -} - -// Write data to a section. - -void -Stream_to_section::do_write(const char* bytes, size_t length) -{ - go_write_export_data (bytes, length); -} diff --git a/gcc-4.8.1/gcc/go/gofrontend/export.h b/gcc-4.8.1/gcc/go/gofrontend/export.h deleted file mode 100644 index c6a481051..000000000 --- a/gcc-4.8.1/gcc/go/gofrontend/export.h +++ /dev/null @@ -1,201 +0,0 @@ -// export.h -- Export declarations in Go frontend. -*- C++ -*- - -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#ifndef GO_EXPORT_H -#define GO_EXPORT_H - -#include "string-dump.h" - -struct sha1_ctx; -class Gogo; -class Import_init; -class Bindings; -class Type; -class Package; - -// Codes used for the builtin types. These are all negative to make -// them easily distinct from the codes assigned by Export::write_type. -// Note that these codes may not be changed! Changing them would -// break existing export data. - -enum Builtin_code -{ - BUILTIN_INT8 = -1, - BUILTIN_INT16 = -2, - BUILTIN_INT32 = -3, - BUILTIN_INT64 = -4, - BUILTIN_UINT8 = -5, - BUILTIN_UINT16 = -6, - BUILTIN_UINT32 = -7, - BUILTIN_UINT64 = -8, - BUILTIN_FLOAT32 = -9, - BUILTIN_FLOAT64 = -10, - BUILTIN_INT = -11, - BUILTIN_UINT = -12, - BUILTIN_UINTPTR = -13, - BUILTIN_BOOL = -15, - BUILTIN_STRING = -16, - BUILTIN_COMPLEX64 = -17, - BUILTIN_COMPLEX128 = -18, - BUILTIN_ERROR = -19, - BUILTIN_BYTE = -20, - BUILTIN_RUNE = -21, - - SMALLEST_BUILTIN_CODE = -21 -}; - -// This class manages exporting Go declarations. It handles the main -// loop of exporting. A pointer to this class is also passed to the -// various specific export implementations. - -class Export : public String_dump -{ - public: - // The Stream class is an interface used to output the exported - // information. The caller should instantiate a child of this - // class. - class Stream - { - public: - Stream(); - virtual ~Stream(); - - // Write a string. Implements the String_dump interface. - void - write_string(const std::string& s) - { this->write_and_sum_bytes(s.data(), s.length()); } - - // Write a nul terminated string. Implements the String_dump interface. - void - write_c_string(const char* s) - { this->write_and_sum_bytes(s, strlen(s)); } - - // Write some bytes. - void - write_bytes(const char* bytes, size_t length) - { this->write_and_sum_bytes(bytes, length); } - - // Return the raw bytes of the checksum data. - std::string - checksum(); - - // Write a checksum string to the stream. This will be called at - // the end of the other output. - void - write_checksum(const std::string&); - - protected: - // This function is called with data to export. This data must be - // made available as a contiguous stream for the importer. - virtual void - do_write(const char* bytes, size_t length) = 0; - - private: - void - write_and_sum_bytes(const char*, size_t); - - // The checksum. - sha1_ctx* checksum_; - }; - - Export(Stream*); - - // The magic code for version 1 export data. - static const int v1_magic_len = 4; - static const char v1_magic[v1_magic_len]; - - // The length of the v1 checksum string. - static const int v1_checksum_len = 20; - - // Register the builtin types. - void - register_builtin_types(Gogo*); - - // Export the identifiers in BINDINGS which are marked for export. - // The exporting is done via a series of calls to THIS->STREAM_. If - // is nothing to export, this->stream_->write will not be called. - // PKGPATH is the package path. - // PACKAGE_PRIORITY is the priority to use for this package. - // IMPORT_INIT_FN is the name of the import initialization function - // for this package; it will be empty if none is needed. - // IMPORTED_INIT_FNS is the list of initialization functions for - // imported packages. - void - export_globals(const std::string& package_name, - const std::string& pkgpath, - int package_priority, - const std::map<std::string, Package*>& imports, - const std::string& import_init_fn, - const std::set<Import_init>& imported_init_fns, - const Bindings* bindings); - - // Write a string to the export stream. - void - write_string(const std::string& s) - { this->stream_->write_string(s); } - - // Write a nul terminated string to the export stream. - void - write_c_string(const char* s) - { this->stream_->write_c_string(s); } - - // Write some bytes to the export stream. - void - write_bytes(const char* bytes, size_t length) - { this->stream_->write_bytes(bytes, length); } - - // Write a name to the export stream. If NAME is empty, write "?". - void - write_name(const std::string& name); - - // Write out a type. This handles references back to previous - // definitions. - void - write_type(const Type*); - - private: - Export(const Export&); - Export& operator=(const Export&); - - // Write out the imported packages. - void - write_imports(const std::map<std::string, Package*>& imports); - - // Write out the imported initialization functions. - void - write_imported_init_fns(const std::string& package_name, int priority, - const std::string&, const std::set<Import_init>&); - - // Register one builtin type. - void - register_builtin_type(Gogo*, const char* name, Builtin_code); - - // Mapping from Type objects to a constant index. - typedef Unordered_map(const Type*, int) Type_refs; - - // The stream to which we are writing data. - Stream* stream_; - // Type mappings. - Type_refs type_refs_; - // Index number of next type. - int type_index_; - // Packages we have written out. - Unordered_set(const Package*) packages_; -}; - -// An export streamer which puts the export stream in a named section. - -class Stream_to_section : public Export::Stream -{ - public: - Stream_to_section(); - - protected: - void - do_write(const char*, size_t); -}; - -#endif // !defined(GO_EXPORT_H) diff --git a/gcc-4.8.1/gcc/go/gofrontend/expressions.cc b/gcc-4.8.1/gcc/go/gofrontend/expressions.cc deleted file mode 100644 index 9abd2247f..000000000 --- a/gcc-4.8.1/gcc/go/gofrontend/expressions.cc +++ /dev/null @@ -1,14467 +0,0 @@ -// expressions.cc -- Go frontend expression handling. - -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "go-system.h" - -#include <algorithm> - -#include "toplev.h" -#include "intl.h" -#include "tree.h" -#include "gimple.h" -#include "tree-iterator.h" -#include "convert.h" -#include "real.h" -#include "realmpfr.h" - -#include "go-c.h" -#include "gogo.h" -#include "types.h" -#include "export.h" -#include "import.h" -#include "statements.h" -#include "lex.h" -#include "runtime.h" -#include "backend.h" -#include "expressions.h" -#include "ast-dump.h" - -// Class Expression. - -Expression::Expression(Expression_classification classification, - Location location) - : classification_(classification), location_(location) -{ -} - -Expression::~Expression() -{ -} - -// Traverse the expressions. - -int -Expression::traverse(Expression** pexpr, Traverse* traverse) -{ - Expression* expr = *pexpr; - if ((traverse->traverse_mask() & Traverse::traverse_expressions) != 0) - { - int t = traverse->expression(pexpr); - if (t == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - else if (t == TRAVERSE_SKIP_COMPONENTS) - return TRAVERSE_CONTINUE; - } - return expr->do_traverse(traverse); -} - -// Traverse subexpressions of this expression. - -int -Expression::traverse_subexpressions(Traverse* traverse) -{ - return this->do_traverse(traverse); -} - -// Default implementation for do_traverse for child classes. - -int -Expression::do_traverse(Traverse*) -{ - return TRAVERSE_CONTINUE; -} - -// This virtual function is called by the parser if the value of this -// expression is being discarded. By default, we give an error. -// Expressions with side effects override. - -bool -Expression::do_discarding_value() -{ - this->unused_value_error(); - return false; -} - -// This virtual function is called to export expressions. This will -// only be used by expressions which may be constant. - -void -Expression::do_export(Export*) const -{ - go_unreachable(); -} - -// Give an error saying that the value of the expression is not used. - -void -Expression::unused_value_error() -{ - this->report_error(_("value computed is not used")); -} - -// Note that this expression is an error. This is called by children -// when they discover an error. - -void -Expression::set_is_error() -{ - this->classification_ = EXPRESSION_ERROR; -} - -// For children to call to report an error conveniently. - -void -Expression::report_error(const char* msg) -{ - error_at(this->location_, "%s", msg); - this->set_is_error(); -} - -// Set types of variables and constants. This is implemented by the -// child class. - -void -Expression::determine_type(const Type_context* context) -{ - this->do_determine_type(context); -} - -// Set types when there is no context. - -void -Expression::determine_type_no_context() -{ - Type_context context; - this->do_determine_type(&context); -} - -// Return a tree handling any conversions which must be done during -// assignment. - -tree -Expression::convert_for_assignment(Translate_context* context, Type* lhs_type, - Type* rhs_type, tree rhs_tree, - Location location) -{ - if (lhs_type->is_error() || rhs_type->is_error()) - return error_mark_node; - - if (rhs_tree == error_mark_node || TREE_TYPE(rhs_tree) == error_mark_node) - return error_mark_node; - - Gogo* gogo = context->gogo(); - - tree lhs_type_tree = type_to_tree(lhs_type->get_backend(gogo)); - if (lhs_type_tree == error_mark_node) - return error_mark_node; - - if (lhs_type->forwarded() != rhs_type->forwarded() - && lhs_type->interface_type() != NULL) - { - if (rhs_type->interface_type() == NULL) - return Expression::convert_type_to_interface(context, lhs_type, - rhs_type, rhs_tree, - location); - else - return Expression::convert_interface_to_interface(context, lhs_type, - rhs_type, rhs_tree, - false, location); - } - else if (lhs_type->forwarded() != rhs_type->forwarded() - && rhs_type->interface_type() != NULL) - return Expression::convert_interface_to_type(context, lhs_type, rhs_type, - rhs_tree, location); - else if (lhs_type->is_slice_type() && rhs_type->is_nil_type()) - { - // Assigning nil to an open array. - go_assert(TREE_CODE(lhs_type_tree) == RECORD_TYPE); - - vec<constructor_elt, va_gc> *init; - vec_alloc(init, 3); - - constructor_elt empty = {NULL, NULL}; - constructor_elt* elt = init->quick_push(empty); - tree field = TYPE_FIELDS(lhs_type_tree); - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), - "__values") == 0); - elt->index = field; - elt->value = fold_convert(TREE_TYPE(field), null_pointer_node); - - elt = init->quick_push(empty); - field = DECL_CHAIN(field); - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), - "__count") == 0); - elt->index = field; - elt->value = fold_convert(TREE_TYPE(field), integer_zero_node); - - elt = init->quick_push(empty); - field = DECL_CHAIN(field); - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), - "__capacity") == 0); - elt->index = field; - elt->value = fold_convert(TREE_TYPE(field), integer_zero_node); - - tree val = build_constructor(lhs_type_tree, init); - TREE_CONSTANT(val) = 1; - - return val; - } - else if (rhs_type->is_nil_type()) - { - // The left hand side should be a pointer type at the tree - // level. - go_assert(POINTER_TYPE_P(lhs_type_tree)); - return fold_convert(lhs_type_tree, null_pointer_node); - } - else if (lhs_type_tree == TREE_TYPE(rhs_tree)) - { - // No conversion is needed. - return rhs_tree; - } - else if (POINTER_TYPE_P(lhs_type_tree) - || INTEGRAL_TYPE_P(lhs_type_tree) - || SCALAR_FLOAT_TYPE_P(lhs_type_tree) - || COMPLEX_FLOAT_TYPE_P(lhs_type_tree)) - return fold_convert_loc(location.gcc_location(), lhs_type_tree, rhs_tree); - else if ((TREE_CODE(lhs_type_tree) == RECORD_TYPE - && TREE_CODE(TREE_TYPE(rhs_tree)) == RECORD_TYPE) - || (TREE_CODE(lhs_type_tree) == ARRAY_TYPE - && TREE_CODE(TREE_TYPE(rhs_tree)) == ARRAY_TYPE)) - { - // Avoid confusion from zero sized variables which may be - // represented as non-zero-sized. - if (int_size_in_bytes(lhs_type_tree) == 0 - || int_size_in_bytes(TREE_TYPE(rhs_tree)) == 0) - return rhs_tree; - - // This conversion must be permitted by Go, or we wouldn't have - // gotten here. - go_assert(int_size_in_bytes(lhs_type_tree) - == int_size_in_bytes(TREE_TYPE(rhs_tree))); - return fold_build1_loc(location.gcc_location(), VIEW_CONVERT_EXPR, - lhs_type_tree, rhs_tree); - } - else - { - go_assert(useless_type_conversion_p(lhs_type_tree, TREE_TYPE(rhs_tree))); - return rhs_tree; - } -} - -// Return a tree for a conversion from a non-interface type to an -// interface type. - -tree -Expression::convert_type_to_interface(Translate_context* context, - Type* lhs_type, Type* rhs_type, - tree rhs_tree, Location location) -{ - Gogo* gogo = context->gogo(); - Interface_type* lhs_interface_type = lhs_type->interface_type(); - bool lhs_is_empty = lhs_interface_type->is_empty(); - - // Since RHS_TYPE is a static type, we can create the interface - // method table at compile time. - - // When setting an interface to nil, we just set both fields to - // NULL. - if (rhs_type->is_nil_type()) - { - Btype* lhs_btype = lhs_type->get_backend(gogo); - return expr_to_tree(gogo->backend()->zero_expression(lhs_btype)); - } - - // This should have been checked already. - go_assert(lhs_interface_type->implements_interface(rhs_type, NULL)); - - tree lhs_type_tree = type_to_tree(lhs_type->get_backend(gogo)); - if (lhs_type_tree == error_mark_node) - return error_mark_node; - - // An interface is a tuple. If LHS_TYPE is an empty interface type, - // then the first field is the type descriptor for RHS_TYPE. - // Otherwise it is the interface method table for RHS_TYPE. - tree first_field_value; - if (lhs_is_empty) - first_field_value = rhs_type->type_descriptor_pointer(gogo, location); - else - { - // Build the interface method table for this interface and this - // object type: a list of function pointers for each interface - // method. - Named_type* rhs_named_type = rhs_type->named_type(); - Struct_type* rhs_struct_type = rhs_type->struct_type(); - bool is_pointer = false; - if (rhs_named_type == NULL && rhs_struct_type == NULL) - { - rhs_named_type = rhs_type->deref()->named_type(); - rhs_struct_type = rhs_type->deref()->struct_type(); - is_pointer = true; - } - tree method_table; - if (rhs_named_type != NULL) - method_table = - rhs_named_type->interface_method_table(gogo, lhs_interface_type, - is_pointer); - else if (rhs_struct_type != NULL) - method_table = - rhs_struct_type->interface_method_table(gogo, lhs_interface_type, - is_pointer); - else - method_table = null_pointer_node; - first_field_value = fold_convert_loc(location.gcc_location(), - const_ptr_type_node, method_table); - } - if (first_field_value == error_mark_node) - return error_mark_node; - - // Start building a constructor for the value we will return. - - vec<constructor_elt, va_gc> *init; - vec_alloc(init, 2); - - constructor_elt empty = {NULL, NULL}; - constructor_elt* elt = init->quick_push(empty); - tree field = TYPE_FIELDS(lhs_type_tree); - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), - (lhs_is_empty ? "__type_descriptor" : "__methods")) == 0); - elt->index = field; - elt->value = fold_convert_loc(location.gcc_location(), TREE_TYPE(field), - first_field_value); - - elt = init->quick_push(empty); - field = DECL_CHAIN(field); - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__object") == 0); - elt->index = field; - - if (rhs_type->points_to() != NULL) - { - // We are assigning a pointer to the interface; the interface - // holds the pointer itself. - elt->value = rhs_tree; - return build_constructor(lhs_type_tree, init); - } - - // We are assigning a non-pointer value to the interface; the - // interface gets a copy of the value in the heap. - - tree object_size = TYPE_SIZE_UNIT(TREE_TYPE(rhs_tree)); - - tree space = gogo->allocate_memory(rhs_type, object_size, location); - space = fold_convert_loc(location.gcc_location(), - build_pointer_type(TREE_TYPE(rhs_tree)), space); - space = save_expr(space); - - tree ref = build_fold_indirect_ref_loc(location.gcc_location(), space); - TREE_THIS_NOTRAP(ref) = 1; - tree set = fold_build2_loc(location.gcc_location(), MODIFY_EXPR, - void_type_node, ref, rhs_tree); - - elt->value = fold_convert_loc(location.gcc_location(), TREE_TYPE(field), - space); - - return build2(COMPOUND_EXPR, lhs_type_tree, set, - build_constructor(lhs_type_tree, init)); -} - -// Return a tree for the type descriptor of RHS_TREE, which has -// interface type RHS_TYPE. If RHS_TREE is nil the result will be -// NULL. - -tree -Expression::get_interface_type_descriptor(Translate_context*, - Type* rhs_type, tree rhs_tree, - Location location) -{ - tree rhs_type_tree = TREE_TYPE(rhs_tree); - go_assert(TREE_CODE(rhs_type_tree) == RECORD_TYPE); - tree rhs_field = TYPE_FIELDS(rhs_type_tree); - tree v = build3(COMPONENT_REF, TREE_TYPE(rhs_field), rhs_tree, rhs_field, - NULL_TREE); - if (rhs_type->interface_type()->is_empty()) - { - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(rhs_field)), - "__type_descriptor") == 0); - return v; - } - - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(rhs_field)), "__methods") - == 0); - go_assert(POINTER_TYPE_P(TREE_TYPE(v))); - v = save_expr(v); - tree v1 = build_fold_indirect_ref_loc(location.gcc_location(), v); - go_assert(TREE_CODE(TREE_TYPE(v1)) == RECORD_TYPE); - tree f = TYPE_FIELDS(TREE_TYPE(v1)); - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(f)), "__type_descriptor") - == 0); - v1 = build3(COMPONENT_REF, TREE_TYPE(f), v1, f, NULL_TREE); - - tree eq = fold_build2_loc(location.gcc_location(), EQ_EXPR, boolean_type_node, - v, fold_convert_loc(location.gcc_location(), - TREE_TYPE(v), - null_pointer_node)); - tree n = fold_convert_loc(location.gcc_location(), TREE_TYPE(v1), - null_pointer_node); - return fold_build3_loc(location.gcc_location(), COND_EXPR, TREE_TYPE(v1), - eq, n, v1); -} - -// Return a tree for the conversion of an interface type to an -// interface type. - -tree -Expression::convert_interface_to_interface(Translate_context* context, - Type *lhs_type, Type *rhs_type, - tree rhs_tree, bool for_type_guard, - Location location) -{ - Gogo* gogo = context->gogo(); - Interface_type* lhs_interface_type = lhs_type->interface_type(); - bool lhs_is_empty = lhs_interface_type->is_empty(); - - tree lhs_type_tree = type_to_tree(lhs_type->get_backend(gogo)); - if (lhs_type_tree == error_mark_node) - return error_mark_node; - - // In the general case this requires runtime examination of the type - // method table to match it up with the interface methods. - - // FIXME: If all of the methods in the right hand side interface - // also appear in the left hand side interface, then we don't need - // to do a runtime check, although we still need to build a new - // method table. - - // Get the type descriptor for the right hand side. This will be - // NULL for a nil interface. - - if (!DECL_P(rhs_tree)) - rhs_tree = save_expr(rhs_tree); - - tree rhs_type_descriptor = - Expression::get_interface_type_descriptor(context, rhs_type, rhs_tree, - location); - - // The result is going to be a two element constructor. - - vec<constructor_elt, va_gc> *init; - vec_alloc (init, 2); - - constructor_elt empty = {NULL, NULL}; - constructor_elt* elt = init->quick_push(empty); - tree field = TYPE_FIELDS(lhs_type_tree); - elt->index = field; - - if (for_type_guard) - { - // A type assertion fails when converting a nil interface. - tree lhs_type_descriptor = lhs_type->type_descriptor_pointer(gogo, - location); - static tree assert_interface_decl; - tree call = Gogo::call_builtin(&assert_interface_decl, - location, - "__go_assert_interface", - 2, - ptr_type_node, - TREE_TYPE(lhs_type_descriptor), - lhs_type_descriptor, - TREE_TYPE(rhs_type_descriptor), - rhs_type_descriptor); - if (call == error_mark_node) - return error_mark_node; - // This will panic if the interface conversion fails. - TREE_NOTHROW(assert_interface_decl) = 0; - elt->value = fold_convert_loc(location.gcc_location(), TREE_TYPE(field), - call); - } - else if (lhs_is_empty) - { - // A convertion to an empty interface always succeeds, and the - // first field is just the type descriptor of the object. - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), - "__type_descriptor") == 0); - elt->value = fold_convert_loc(location.gcc_location(), - TREE_TYPE(field), rhs_type_descriptor); - } - else - { - // A conversion to a non-empty interface may fail, but unlike a - // type assertion converting nil will always succeed. - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__methods") - == 0); - tree lhs_type_descriptor = lhs_type->type_descriptor_pointer(gogo, - location); - static tree convert_interface_decl; - tree call = Gogo::call_builtin(&convert_interface_decl, - location, - "__go_convert_interface", - 2, - ptr_type_node, - TREE_TYPE(lhs_type_descriptor), - lhs_type_descriptor, - TREE_TYPE(rhs_type_descriptor), - rhs_type_descriptor); - if (call == error_mark_node) - return error_mark_node; - // This will panic if the interface conversion fails. - TREE_NOTHROW(convert_interface_decl) = 0; - elt->value = fold_convert_loc(location.gcc_location(), TREE_TYPE(field), - call); - } - - // The second field is simply the object pointer. - - elt = init->quick_push(empty); - field = DECL_CHAIN(field); - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__object") == 0); - elt->index = field; - - tree rhs_type_tree = TREE_TYPE(rhs_tree); - go_assert(TREE_CODE(rhs_type_tree) == RECORD_TYPE); - tree rhs_field = DECL_CHAIN(TYPE_FIELDS(rhs_type_tree)); - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(rhs_field)), "__object") == 0); - elt->value = build3(COMPONENT_REF, TREE_TYPE(rhs_field), rhs_tree, rhs_field, - NULL_TREE); - - return build_constructor(lhs_type_tree, init); -} - -// Return a tree for the conversion of an interface type to a -// non-interface type. - -tree -Expression::convert_interface_to_type(Translate_context* context, - Type *lhs_type, Type* rhs_type, - tree rhs_tree, Location location) -{ - Gogo* gogo = context->gogo(); - tree rhs_type_tree = TREE_TYPE(rhs_tree); - - tree lhs_type_tree = type_to_tree(lhs_type->get_backend(gogo)); - if (lhs_type_tree == error_mark_node) - return error_mark_node; - - // Call a function to check that the type is valid. The function - // will panic with an appropriate runtime type error if the type is - // not valid. - - tree lhs_type_descriptor = lhs_type->type_descriptor_pointer(gogo, location); - - if (!DECL_P(rhs_tree)) - rhs_tree = save_expr(rhs_tree); - - tree rhs_type_descriptor = - Expression::get_interface_type_descriptor(context, rhs_type, rhs_tree, - location); - - tree rhs_inter_descriptor = rhs_type->type_descriptor_pointer(gogo, - location); - - static tree check_interface_type_decl; - tree call = Gogo::call_builtin(&check_interface_type_decl, - location, - "__go_check_interface_type", - 3, - void_type_node, - TREE_TYPE(lhs_type_descriptor), - lhs_type_descriptor, - TREE_TYPE(rhs_type_descriptor), - rhs_type_descriptor, - TREE_TYPE(rhs_inter_descriptor), - rhs_inter_descriptor); - if (call == error_mark_node) - return error_mark_node; - // This call will panic if the conversion is invalid. - TREE_NOTHROW(check_interface_type_decl) = 0; - - // If the call succeeds, pull out the value. - go_assert(TREE_CODE(rhs_type_tree) == RECORD_TYPE); - tree rhs_field = DECL_CHAIN(TYPE_FIELDS(rhs_type_tree)); - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(rhs_field)), "__object") == 0); - tree val = build3(COMPONENT_REF, TREE_TYPE(rhs_field), rhs_tree, rhs_field, - NULL_TREE); - - // If the value is a pointer, then it is the value we want. - // Otherwise it points to the value. - if (lhs_type->points_to() == NULL) - { - val = fold_convert_loc(location.gcc_location(), - build_pointer_type(lhs_type_tree), val); - val = build_fold_indirect_ref_loc(location.gcc_location(), val); - } - - return build2(COMPOUND_EXPR, lhs_type_tree, call, - fold_convert_loc(location.gcc_location(), lhs_type_tree, val)); -} - -// Convert an expression to a tree. This is implemented by the child -// class. Not that it is not in general safe to call this multiple -// times for a single expression, but that we don't catch such errors. - -tree -Expression::get_tree(Translate_context* context) -{ - // The child may have marked this expression as having an error. - if (this->classification_ == EXPRESSION_ERROR) - return error_mark_node; - - return this->do_get_tree(context); -} - -// Return a tree for VAL in TYPE. - -tree -Expression::integer_constant_tree(mpz_t val, tree type) -{ - if (type == error_mark_node) - return error_mark_node; - else if (TREE_CODE(type) == INTEGER_TYPE) - return double_int_to_tree(type, - mpz_get_double_int(type, val, true)); - else if (TREE_CODE(type) == REAL_TYPE) - { - mpfr_t fval; - mpfr_init_set_z(fval, val, GMP_RNDN); - tree ret = Expression::float_constant_tree(fval, type); - mpfr_clear(fval); - return ret; - } - else if (TREE_CODE(type) == COMPLEX_TYPE) - { - mpfr_t fval; - mpfr_init_set_z(fval, val, GMP_RNDN); - tree real = Expression::float_constant_tree(fval, TREE_TYPE(type)); - mpfr_clear(fval); - tree imag = build_real_from_int_cst(TREE_TYPE(type), - integer_zero_node); - return build_complex(type, real, imag); - } - else - go_unreachable(); -} - -// Return a tree for VAL in TYPE. - -tree -Expression::float_constant_tree(mpfr_t val, tree type) -{ - if (type == error_mark_node) - return error_mark_node; - else if (TREE_CODE(type) == INTEGER_TYPE) - { - mpz_t ival; - mpz_init(ival); - mpfr_get_z(ival, val, GMP_RNDN); - tree ret = Expression::integer_constant_tree(ival, type); - mpz_clear(ival); - return ret; - } - else if (TREE_CODE(type) == REAL_TYPE) - { - REAL_VALUE_TYPE r1; - real_from_mpfr(&r1, val, type, GMP_RNDN); - REAL_VALUE_TYPE r2; - real_convert(&r2, TYPE_MODE(type), &r1); - return build_real(type, r2); - } - else if (TREE_CODE(type) == COMPLEX_TYPE) - { - REAL_VALUE_TYPE r1; - real_from_mpfr(&r1, val, TREE_TYPE(type), GMP_RNDN); - REAL_VALUE_TYPE r2; - real_convert(&r2, TYPE_MODE(TREE_TYPE(type)), &r1); - tree imag = build_real_from_int_cst(TREE_TYPE(type), - integer_zero_node); - return build_complex(type, build_real(TREE_TYPE(type), r2), imag); - } - else - go_unreachable(); -} - -// Return a tree for REAL/IMAG in TYPE. - -tree -Expression::complex_constant_tree(mpfr_t real, mpfr_t imag, tree type) -{ - if (type == error_mark_node) - return error_mark_node; - else if (TREE_CODE(type) == INTEGER_TYPE || TREE_CODE(type) == REAL_TYPE) - return Expression::float_constant_tree(real, type); - else if (TREE_CODE(type) == COMPLEX_TYPE) - { - REAL_VALUE_TYPE r1; - real_from_mpfr(&r1, real, TREE_TYPE(type), GMP_RNDN); - REAL_VALUE_TYPE r2; - real_convert(&r2, TYPE_MODE(TREE_TYPE(type)), &r1); - - REAL_VALUE_TYPE r3; - real_from_mpfr(&r3, imag, TREE_TYPE(type), GMP_RNDN); - REAL_VALUE_TYPE r4; - real_convert(&r4, TYPE_MODE(TREE_TYPE(type)), &r3); - - return build_complex(type, build_real(TREE_TYPE(type), r2), - build_real(TREE_TYPE(type), r4)); - } - else - go_unreachable(); -} - -// Return a tree which evaluates to true if VAL, of arbitrary integer -// type, is negative or is more than the maximum value of BOUND_TYPE. -// If SOFAR is not NULL, it is or'red into the result. The return -// value may be NULL if SOFAR is NULL. - -tree -Expression::check_bounds(tree val, tree bound_type, tree sofar, - Location loc) -{ - tree val_type = TREE_TYPE(val); - tree ret = NULL_TREE; - - if (!TYPE_UNSIGNED(val_type)) - { - ret = fold_build2_loc(loc.gcc_location(), LT_EXPR, boolean_type_node, val, - build_int_cst(val_type, 0)); - if (ret == boolean_false_node) - ret = NULL_TREE; - } - - HOST_WIDE_INT val_type_size = int_size_in_bytes(val_type); - HOST_WIDE_INT bound_type_size = int_size_in_bytes(bound_type); - go_assert(val_type_size != -1 && bound_type_size != -1); - if (val_type_size > bound_type_size - || (val_type_size == bound_type_size - && TYPE_UNSIGNED(val_type) - && !TYPE_UNSIGNED(bound_type))) - { - tree max = TYPE_MAX_VALUE(bound_type); - tree big = fold_build2_loc(loc.gcc_location(), GT_EXPR, boolean_type_node, - val, fold_convert_loc(loc.gcc_location(), - val_type, max)); - if (big == boolean_false_node) - ; - else if (ret == NULL_TREE) - ret = big; - else - ret = fold_build2_loc(loc.gcc_location(), TRUTH_OR_EXPR, - boolean_type_node, ret, big); - } - - if (ret == NULL_TREE) - return sofar; - else if (sofar == NULL_TREE) - return ret; - else - return fold_build2_loc(loc.gcc_location(), TRUTH_OR_EXPR, boolean_type_node, - sofar, ret); -} - -void -Expression::dump_expression(Ast_dump_context* ast_dump_context) const -{ - this->do_dump_expression(ast_dump_context); -} - -// Error expressions. This are used to avoid cascading errors. - -class Error_expression : public Expression -{ - public: - Error_expression(Location location) - : Expression(EXPRESSION_ERROR, location) - { } - - protected: - bool - do_is_constant() const - { return true; } - - bool - do_numeric_constant_value(Numeric_constant* nc) const - { - nc->set_unsigned_long(NULL, 0); - return true; - } - - bool - do_discarding_value() - { return true; } - - Type* - do_type() - { return Type::make_error_type(); } - - void - do_determine_type(const Type_context*) - { } - - Expression* - do_copy() - { return this; } - - bool - do_is_addressable() const - { return true; } - - tree - do_get_tree(Translate_context*) - { return error_mark_node; } - - void - do_dump_expression(Ast_dump_context*) const; -}; - -// Dump the ast representation for an error expression to a dump context. - -void -Error_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const -{ - ast_dump_context->ostream() << "_Error_" ; -} - -Expression* -Expression::make_error(Location location) -{ - return new Error_expression(location); -} - -// An expression which is really a type. This is used during parsing. -// It is an error if these survive after lowering. - -class -Type_expression : public Expression -{ - public: - Type_expression(Type* type, Location location) - : Expression(EXPRESSION_TYPE, location), - type_(type) - { } - - protected: - int - do_traverse(Traverse* traverse) - { return Type::traverse(this->type_, traverse); } - - Type* - do_type() - { return this->type_; } - - void - do_determine_type(const Type_context*) - { } - - void - do_check_types(Gogo*) - { this->report_error(_("invalid use of type")); } - - Expression* - do_copy() - { return this; } - - tree - do_get_tree(Translate_context*) - { go_unreachable(); } - - void do_dump_expression(Ast_dump_context*) const; - - private: - // The type which we are representing as an expression. - Type* type_; -}; - -void -Type_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const -{ - ast_dump_context->dump_type(this->type_); -} - -Expression* -Expression::make_type(Type* type, Location location) -{ - return new Type_expression(type, location); -} - -// Class Parser_expression. - -Type* -Parser_expression::do_type() -{ - // We should never really ask for the type of a Parser_expression. - // However, it can happen, at least when we have an invalid const - // whose initializer refers to the const itself. In that case we - // may ask for the type when lowering the const itself. - go_assert(saw_errors()); - return Type::make_error_type(); -} - -// Class Var_expression. - -// Lower a variable expression. Here we just make sure that the -// initialization expression of the variable has been lowered. This -// ensures that we will be able to determine the type of the variable -// if necessary. - -Expression* -Var_expression::do_lower(Gogo* gogo, Named_object* function, - Statement_inserter* inserter, int) -{ - if (this->variable_->is_variable()) - { - Variable* var = this->variable_->var_value(); - // This is either a local variable or a global variable. A - // reference to a variable which is local to an enclosing - // function will be a reference to a field in a closure. - if (var->is_global()) - { - function = NULL; - inserter = NULL; - } - var->lower_init_expression(gogo, function, inserter); - } - return this; -} - -// Return the type of a reference to a variable. - -Type* -Var_expression::do_type() -{ - if (this->variable_->is_variable()) - return this->variable_->var_value()->type(); - else if (this->variable_->is_result_variable()) - return this->variable_->result_var_value()->type(); - else - go_unreachable(); -} - -// Determine the type of a reference to a variable. - -void -Var_expression::do_determine_type(const Type_context*) -{ - if (this->variable_->is_variable()) - this->variable_->var_value()->determine_type(); -} - -// Something takes the address of this variable. This means that we -// may want to move the variable onto the heap. - -void -Var_expression::do_address_taken(bool escapes) -{ - if (!escapes) - { - if (this->variable_->is_variable()) - this->variable_->var_value()->set_non_escaping_address_taken(); - else if (this->variable_->is_result_variable()) - this->variable_->result_var_value()->set_non_escaping_address_taken(); - else - go_unreachable(); - } - else - { - if (this->variable_->is_variable()) - this->variable_->var_value()->set_address_taken(); - else if (this->variable_->is_result_variable()) - this->variable_->result_var_value()->set_address_taken(); - else - go_unreachable(); - } -} - -// Get the tree for a reference to a variable. - -tree -Var_expression::do_get_tree(Translate_context* context) -{ - Bvariable* bvar = this->variable_->get_backend_variable(context->gogo(), - context->function()); - tree ret = var_to_tree(bvar); - if (ret == error_mark_node) - return error_mark_node; - bool is_in_heap; - if (this->variable_->is_variable()) - is_in_heap = this->variable_->var_value()->is_in_heap(); - else if (this->variable_->is_result_variable()) - is_in_heap = this->variable_->result_var_value()->is_in_heap(); - else - go_unreachable(); - if (is_in_heap) - { - ret = build_fold_indirect_ref_loc(this->location().gcc_location(), ret); - TREE_THIS_NOTRAP(ret) = 1; - } - return ret; -} - -// Ast dump for variable expression. - -void -Var_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const -{ - ast_dump_context->ostream() << this->variable_->name() ; -} - -// Make a reference to a variable in an expression. - -Expression* -Expression::make_var_reference(Named_object* var, Location location) -{ - if (var->is_sink()) - return Expression::make_sink(location); - - // FIXME: Creating a new object for each reference to a variable is - // wasteful. - return new Var_expression(var, location); -} - -// Class Temporary_reference_expression. - -// The type. - -Type* -Temporary_reference_expression::do_type() -{ - return this->statement_->type(); -} - -// Called if something takes the address of this temporary variable. -// We never have to move temporary variables to the heap, but we do -// need to know that they must live in the stack rather than in a -// register. - -void -Temporary_reference_expression::do_address_taken(bool) -{ - this->statement_->set_is_address_taken(); -} - -// Get a tree referring to the variable. - -tree -Temporary_reference_expression::do_get_tree(Translate_context* context) -{ - Bvariable* bvar = this->statement_->get_backend_variable(context); - - // The gcc backend can't represent the same set of recursive types - // that the Go frontend can. In some cases this means that a - // temporary variable won't have the right backend type. Correct - // that here by adding a type cast. We need to use base() to push - // the circularity down one level. - tree ret = var_to_tree(bvar); - if (!this->is_lvalue_ - && POINTER_TYPE_P(TREE_TYPE(ret)) - && VOID_TYPE_P(TREE_TYPE(TREE_TYPE(ret)))) - { - Btype* type_btype = this->type()->base()->get_backend(context->gogo()); - tree type_tree = type_to_tree(type_btype); - ret = fold_convert_loc(this->location().gcc_location(), type_tree, ret); - } - return ret; -} - -// Ast dump for temporary reference. - -void -Temporary_reference_expression::do_dump_expression( - Ast_dump_context* ast_dump_context) const -{ - ast_dump_context->dump_temp_variable_name(this->statement_); -} - -// Make a reference to a temporary variable. - -Temporary_reference_expression* -Expression::make_temporary_reference(Temporary_statement* statement, - Location location) -{ - return new Temporary_reference_expression(statement, location); -} - -// Class Set_and_use_temporary_expression. - -// Return the type. - -Type* -Set_and_use_temporary_expression::do_type() -{ - return this->statement_->type(); -} - -// Take the address. - -void -Set_and_use_temporary_expression::do_address_taken(bool) -{ - this->statement_->set_is_address_taken(); -} - -// Return the backend representation. - -tree -Set_and_use_temporary_expression::do_get_tree(Translate_context* context) -{ - Bvariable* bvar = this->statement_->get_backend_variable(context); - tree var_tree = var_to_tree(bvar); - tree expr_tree = this->expr_->get_tree(context); - if (var_tree == error_mark_node || expr_tree == error_mark_node) - return error_mark_node; - Location loc = this->location(); - return build2_loc(loc.gcc_location(), COMPOUND_EXPR, TREE_TYPE(var_tree), - build2_loc(loc.gcc_location(), MODIFY_EXPR, void_type_node, - var_tree, expr_tree), - var_tree); -} - -// Dump. - -void -Set_and_use_temporary_expression::do_dump_expression( - Ast_dump_context* ast_dump_context) const -{ - ast_dump_context->ostream() << '('; - ast_dump_context->dump_temp_variable_name(this->statement_); - ast_dump_context->ostream() << " = "; - this->expr_->dump_expression(ast_dump_context); - ast_dump_context->ostream() << ')'; -} - -// Make a set-and-use temporary. - -Set_and_use_temporary_expression* -Expression::make_set_and_use_temporary(Temporary_statement* statement, - Expression* expr, Location location) -{ - return new Set_and_use_temporary_expression(statement, expr, location); -} - -// A sink expression--a use of the blank identifier _. - -class Sink_expression : public Expression -{ - public: - Sink_expression(Location location) - : Expression(EXPRESSION_SINK, location), - type_(NULL), var_(NULL_TREE) - { } - - protected: - bool - do_discarding_value() - { return true; } - - Type* - do_type(); - - void - do_determine_type(const Type_context*); - - Expression* - do_copy() - { return new Sink_expression(this->location()); } - - tree - do_get_tree(Translate_context*); - - void - do_dump_expression(Ast_dump_context*) const; - - private: - // The type of this sink variable. - Type* type_; - // The temporary variable we generate. - tree var_; -}; - -// Return the type of a sink expression. - -Type* -Sink_expression::do_type() -{ - if (this->type_ == NULL) - return Type::make_sink_type(); - return this->type_; -} - -// Determine the type of a sink expression. - -void -Sink_expression::do_determine_type(const Type_context* context) -{ - if (context->type != NULL) - this->type_ = context->type; -} - -// Return a temporary variable for a sink expression. This will -// presumably be a write-only variable which the middle-end will drop. - -tree -Sink_expression::do_get_tree(Translate_context* context) -{ - if (this->var_ == NULL_TREE) - { - go_assert(this->type_ != NULL && !this->type_->is_sink_type()); - Btype* bt = this->type_->get_backend(context->gogo()); - this->var_ = create_tmp_var(type_to_tree(bt), "blank"); - } - return this->var_; -} - -// Ast dump for sink expression. - -void -Sink_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const -{ - ast_dump_context->ostream() << "_" ; -} - -// Make a sink expression. - -Expression* -Expression::make_sink(Location location) -{ - return new Sink_expression(location); -} - -// Class Func_expression. - -// FIXME: Can a function expression appear in a constant expression? -// The value is unchanging. Initializing a constant to the address of -// a function seems like it could work, though there might be little -// point to it. - -// Traversal. - -int -Func_expression::do_traverse(Traverse* traverse) -{ - return (this->closure_ == NULL - ? TRAVERSE_CONTINUE - : Expression::traverse(&this->closure_, traverse)); -} - -// Return the type of a function expression. - -Type* -Func_expression::do_type() -{ - if (this->function_->is_function()) - return this->function_->func_value()->type(); - else if (this->function_->is_function_declaration()) - return this->function_->func_declaration_value()->type(); - else - go_unreachable(); -} - -// Get the tree for a function expression without evaluating the -// closure. - -tree -Func_expression::get_tree_without_closure(Gogo* gogo) -{ - Function_type* fntype; - if (this->function_->is_function()) - fntype = this->function_->func_value()->type(); - else if (this->function_->is_function_declaration()) - fntype = this->function_->func_declaration_value()->type(); - else - go_unreachable(); - - // Builtin functions are handled specially by Call_expression. We - // can't take their address. - if (fntype->is_builtin()) - { - error_at(this->location(), - "invalid use of special builtin function %qs; must be called", - this->function_->name().c_str()); - return error_mark_node; - } - - Named_object* no = this->function_; - - tree id = no->get_id(gogo); - if (id == error_mark_node) - return error_mark_node; - - tree fndecl; - if (no->is_function()) - fndecl = no->func_value()->get_or_make_decl(gogo, no, id); - else if (no->is_function_declaration()) - fndecl = no->func_declaration_value()->get_or_make_decl(gogo, no, id); - else - go_unreachable(); - - if (fndecl == error_mark_node) - return error_mark_node; - - return build_fold_addr_expr_loc(this->location().gcc_location(), fndecl); -} - -// Get the tree for a function expression. This is used when we take -// the address of a function rather than simply calling it. If the -// function has a closure, we must use a trampoline. - -tree -Func_expression::do_get_tree(Translate_context* context) -{ - Gogo* gogo = context->gogo(); - - tree fnaddr = this->get_tree_without_closure(gogo); - if (fnaddr == error_mark_node) - return error_mark_node; - - go_assert(TREE_CODE(fnaddr) == ADDR_EXPR - && TREE_CODE(TREE_OPERAND(fnaddr, 0)) == FUNCTION_DECL); - TREE_ADDRESSABLE(TREE_OPERAND(fnaddr, 0)) = 1; - - // If there is no closure, that is all have to do. - if (this->closure_ == NULL) - return fnaddr; - - go_assert(this->function_->func_value()->enclosing() != NULL); - - // Get the value of the closure. This will be a pointer to space - // allocated on the heap. - tree closure_tree = this->closure_->get_tree(context); - if (closure_tree == error_mark_node) - return error_mark_node; - go_assert(POINTER_TYPE_P(TREE_TYPE(closure_tree))); - - // Now we need to build some code on the heap. This code will load - // the static chain pointer with the closure and then jump to the - // body of the function. The normal gcc approach is to build the - // code on the stack. Unfortunately we can not do that, as Go - // permits us to return the function pointer. - - return gogo->make_trampoline(fnaddr, closure_tree, this->location()); -} - -// Ast dump for function. - -void -Func_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const -{ - ast_dump_context->ostream() << this->function_->name(); - if (this->closure_ != NULL) - { - ast_dump_context->ostream() << " {closure = "; - this->closure_->dump_expression(ast_dump_context); - ast_dump_context->ostream() << "}"; - } -} - -// Make a reference to a function in an expression. - -Expression* -Expression::make_func_reference(Named_object* function, Expression* closure, - Location location) -{ - return new Func_expression(function, closure, location); -} - -// Class Unknown_expression. - -// Return the name of an unknown expression. - -const std::string& -Unknown_expression::name() const -{ - return this->named_object_->name(); -} - -// Lower a reference to an unknown name. - -Expression* -Unknown_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int) -{ - Location location = this->location(); - Named_object* no = this->named_object_; - Named_object* real; - if (!no->is_unknown()) - real = no; - else - { - real = no->unknown_value()->real_named_object(); - if (real == NULL) - { - if (this->is_composite_literal_key_) - return this; - if (!this->no_error_message_) - error_at(location, "reference to undefined name %qs", - this->named_object_->message_name().c_str()); - return Expression::make_error(location); - } - } - switch (real->classification()) - { - case Named_object::NAMED_OBJECT_CONST: - return Expression::make_const_reference(real, location); - case Named_object::NAMED_OBJECT_TYPE: - return Expression::make_type(real->type_value(), location); - case Named_object::NAMED_OBJECT_TYPE_DECLARATION: - if (this->is_composite_literal_key_) - return this; - if (!this->no_error_message_) - error_at(location, "reference to undefined type %qs", - real->message_name().c_str()); - return Expression::make_error(location); - case Named_object::NAMED_OBJECT_VAR: - real->var_value()->set_is_used(); - return Expression::make_var_reference(real, location); - case Named_object::NAMED_OBJECT_FUNC: - case Named_object::NAMED_OBJECT_FUNC_DECLARATION: - return Expression::make_func_reference(real, NULL, location); - case Named_object::NAMED_OBJECT_PACKAGE: - if (this->is_composite_literal_key_) - return this; - if (!this->no_error_message_) - error_at(location, "unexpected reference to package"); - return Expression::make_error(location); - default: - go_unreachable(); - } -} - -// Dump the ast representation for an unknown expression to a dump context. - -void -Unknown_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const -{ - ast_dump_context->ostream() << "_Unknown_(" << this->named_object_->name() - << ")"; -} - -// Make a reference to an unknown name. - -Unknown_expression* -Expression::make_unknown_reference(Named_object* no, Location location) -{ - return new Unknown_expression(no, location); -} - -// A boolean expression. - -class Boolean_expression : public Expression -{ - public: - Boolean_expression(bool val, Location location) - : Expression(EXPRESSION_BOOLEAN, location), - val_(val), type_(NULL) - { } - - static Expression* - do_import(Import*); - - protected: - bool - do_is_constant() const - { return true; } - - Type* - do_type(); - - void - do_determine_type(const Type_context*); - - Expression* - do_copy() - { return this; } - - tree - do_get_tree(Translate_context*) - { return this->val_ ? boolean_true_node : boolean_false_node; } - - void - do_export(Export* exp) const - { exp->write_c_string(this->val_ ? "true" : "false"); } - - void - do_dump_expression(Ast_dump_context* ast_dump_context) const - { ast_dump_context->ostream() << (this->val_ ? "true" : "false"); } - - private: - // The constant. - bool val_; - // The type as determined by context. - Type* type_; -}; - -// Get the type. - -Type* -Boolean_expression::do_type() -{ - if (this->type_ == NULL) - this->type_ = Type::make_boolean_type(); - return this->type_; -} - -// Set the type from the context. - -void -Boolean_expression::do_determine_type(const Type_context* context) -{ - if (this->type_ != NULL && !this->type_->is_abstract()) - ; - else if (context->type != NULL && context->type->is_boolean_type()) - this->type_ = context->type; - else if (!context->may_be_abstract) - this->type_ = Type::lookup_bool_type(); -} - -// Import a boolean constant. - -Expression* -Boolean_expression::do_import(Import* imp) -{ - if (imp->peek_char() == 't') - { - imp->require_c_string("true"); - return Expression::make_boolean(true, imp->location()); - } - else - { - imp->require_c_string("false"); - return Expression::make_boolean(false, imp->location()); - } -} - -// Make a boolean expression. - -Expression* -Expression::make_boolean(bool val, Location location) -{ - return new Boolean_expression(val, location); -} - -// Class String_expression. - -// Get the type. - -Type* -String_expression::do_type() -{ - if (this->type_ == NULL) - this->type_ = Type::make_string_type(); - return this->type_; -} - -// Set the type from the context. - -void -String_expression::do_determine_type(const Type_context* context) -{ - if (this->type_ != NULL && !this->type_->is_abstract()) - ; - else if (context->type != NULL && context->type->is_string_type()) - this->type_ = context->type; - else if (!context->may_be_abstract) - this->type_ = Type::lookup_string_type(); -} - -// Build a string constant. - -tree -String_expression::do_get_tree(Translate_context* context) -{ - return context->gogo()->go_string_constant_tree(this->val_); -} - - // Write string literal to string dump. - -void -String_expression::export_string(String_dump* exp, - const String_expression* str) -{ - std::string s; - s.reserve(str->val_.length() * 4 + 2); - s += '"'; - for (std::string::const_iterator p = str->val_.begin(); - p != str->val_.end(); - ++p) - { - if (*p == '\\' || *p == '"') - { - s += '\\'; - s += *p; - } - else if (*p >= 0x20 && *p < 0x7f) - s += *p; - else if (*p == '\n') - s += "\\n"; - else if (*p == '\t') - s += "\\t"; - else - { - s += "\\x"; - unsigned char c = *p; - unsigned int dig = c >> 4; - s += dig < 10 ? '0' + dig : 'A' + dig - 10; - dig = c & 0xf; - s += dig < 10 ? '0' + dig : 'A' + dig - 10; - } - } - s += '"'; - exp->write_string(s); -} - -// Export a string expression. - -void -String_expression::do_export(Export* exp) const -{ - String_expression::export_string(exp, this); -} - -// Import a string expression. - -Expression* -String_expression::do_import(Import* imp) -{ - imp->require_c_string("\""); - std::string val; - while (true) - { - int c = imp->get_char(); - if (c == '"' || c == -1) - break; - if (c != '\\') - val += static_cast<char>(c); - else - { - c = imp->get_char(); - if (c == '\\' || c == '"') - val += static_cast<char>(c); - else if (c == 'n') - val += '\n'; - else if (c == 't') - val += '\t'; - else if (c == 'x') - { - c = imp->get_char(); - unsigned int vh = c >= '0' && c <= '9' ? c - '0' : c - 'A' + 10; - c = imp->get_char(); - unsigned int vl = c >= '0' && c <= '9' ? c - '0' : c - 'A' + 10; - char v = (vh << 4) | vl; - val += v; - } - else - { - error_at(imp->location(), "bad string constant"); - return Expression::make_error(imp->location()); - } - } - } - return Expression::make_string(val, imp->location()); -} - -// Ast dump for string expression. - -void -String_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const -{ - String_expression::export_string(ast_dump_context, this); -} - -// Make a string expression. - -Expression* -Expression::make_string(const std::string& val, Location location) -{ - return new String_expression(val, location); -} - -// Make an integer expression. - -class Integer_expression : public Expression -{ - public: - Integer_expression(const mpz_t* val, Type* type, bool is_character_constant, - Location location) - : Expression(EXPRESSION_INTEGER, location), - type_(type), is_character_constant_(is_character_constant) - { mpz_init_set(this->val_, *val); } - - static Expression* - do_import(Import*); - - // Write VAL to string dump. - static void - export_integer(String_dump* exp, const mpz_t val); - - // Write VAL to dump context. - static void - dump_integer(Ast_dump_context* ast_dump_context, const mpz_t val); - - protected: - bool - do_is_constant() const - { return true; } - - bool - do_numeric_constant_value(Numeric_constant* nc) const; - - Type* - do_type(); - - void - do_determine_type(const Type_context* context); - - void - do_check_types(Gogo*); - - tree - do_get_tree(Translate_context*); - - Expression* - do_copy() - { - if (this->is_character_constant_) - return Expression::make_character(&this->val_, this->type_, - this->location()); - else - return Expression::make_integer(&this->val_, this->type_, - this->location()); - } - - void - do_export(Export*) const; - - void - do_dump_expression(Ast_dump_context*) const; - - private: - // The integer value. - mpz_t val_; - // The type so far. - Type* type_; - // Whether this is a character constant. - bool is_character_constant_; -}; - -// Return a numeric constant for this expression. We have to mark -// this as a character when appropriate. - -bool -Integer_expression::do_numeric_constant_value(Numeric_constant* nc) const -{ - if (this->is_character_constant_) - nc->set_rune(this->type_, this->val_); - else - nc->set_int(this->type_, this->val_); - return true; -} - -// Return the current type. If we haven't set the type yet, we return -// an abstract integer type. - -Type* -Integer_expression::do_type() -{ - if (this->type_ == NULL) - { - if (this->is_character_constant_) - this->type_ = Type::make_abstract_character_type(); - else - this->type_ = Type::make_abstract_integer_type(); - } - return this->type_; -} - -// Set the type of the integer value. Here we may switch from an -// abstract type to a real type. - -void -Integer_expression::do_determine_type(const Type_context* context) -{ - if (this->type_ != NULL && !this->type_->is_abstract()) - ; - else if (context->type != NULL && context->type->is_numeric_type()) - this->type_ = context->type; - else if (!context->may_be_abstract) - { - if (this->is_character_constant_) - this->type_ = Type::lookup_integer_type("int32"); - else - this->type_ = Type::lookup_integer_type("int"); - } -} - -// Check the type of an integer constant. - -void -Integer_expression::do_check_types(Gogo*) -{ - Type* type = this->type_; - if (type == NULL) - return; - Numeric_constant nc; - if (this->is_character_constant_) - nc.set_rune(NULL, this->val_); - else - nc.set_int(NULL, this->val_); - if (!nc.set_type(type, true, this->location())) - this->set_is_error(); -} - -// Get a tree for an integer constant. - -tree -Integer_expression::do_get_tree(Translate_context* context) -{ - Gogo* gogo = context->gogo(); - tree type; - if (this->type_ != NULL && !this->type_->is_abstract()) - type = type_to_tree(this->type_->get_backend(gogo)); - else if (this->type_ != NULL && this->type_->float_type() != NULL) - { - // We are converting to an abstract floating point type. - Type* ftype = Type::lookup_float_type("float64"); - type = type_to_tree(ftype->get_backend(gogo)); - } - else if (this->type_ != NULL && this->type_->complex_type() != NULL) - { - // We are converting to an abstract complex type. - Type* ctype = Type::lookup_complex_type("complex128"); - type = type_to_tree(ctype->get_backend(gogo)); - } - else - { - // If we still have an abstract type here, then this is being - // used in a constant expression which didn't get reduced for - // some reason. Use a type which will fit the value. We use <, - // not <=, because we need an extra bit for the sign bit. - int bits = mpz_sizeinbase(this->val_, 2); - Type* int_type = Type::lookup_integer_type("int"); - if (bits < int_type->integer_type()->bits()) - type = type_to_tree(int_type->get_backend(gogo)); - else if (bits < 64) - { - Type* t = Type::lookup_integer_type("int64"); - type = type_to_tree(t->get_backend(gogo)); - } - else - type = long_long_integer_type_node; - } - return Expression::integer_constant_tree(this->val_, type); -} - -// Write VAL to export data. - -void -Integer_expression::export_integer(String_dump* exp, const mpz_t val) -{ - char* s = mpz_get_str(NULL, 10, val); - exp->write_c_string(s); - free(s); -} - -// Export an integer in a constant expression. - -void -Integer_expression::do_export(Export* exp) const -{ - Integer_expression::export_integer(exp, this->val_); - if (this->is_character_constant_) - exp->write_c_string("'"); - // A trailing space lets us reliably identify the end of the number. - exp->write_c_string(" "); -} - -// Import an integer, floating point, or complex value. This handles -// all these types because they all start with digits. - -Expression* -Integer_expression::do_import(Import* imp) -{ - std::string num = imp->read_identifier(); - imp->require_c_string(" "); - if (!num.empty() && num[num.length() - 1] == 'i') - { - mpfr_t real; - size_t plus_pos = num.find('+', 1); - size_t minus_pos = num.find('-', 1); - size_t pos; - if (plus_pos == std::string::npos) - pos = minus_pos; - else if (minus_pos == std::string::npos) - pos = plus_pos; - else - { - error_at(imp->location(), "bad number in import data: %qs", - num.c_str()); - return Expression::make_error(imp->location()); - } - if (pos == std::string::npos) - mpfr_set_ui(real, 0, GMP_RNDN); - else - { - std::string real_str = num.substr(0, pos); - if (mpfr_init_set_str(real, real_str.c_str(), 10, GMP_RNDN) != 0) - { - error_at(imp->location(), "bad number in import data: %qs", - real_str.c_str()); - return Expression::make_error(imp->location()); - } - } - - std::string imag_str; - if (pos == std::string::npos) - imag_str = num; - else - imag_str = num.substr(pos); - imag_str = imag_str.substr(0, imag_str.size() - 1); - mpfr_t imag; - if (mpfr_init_set_str(imag, imag_str.c_str(), 10, GMP_RNDN) != 0) - { - error_at(imp->location(), "bad number in import data: %qs", - imag_str.c_str()); - return Expression::make_error(imp->location()); - } - Expression* ret = Expression::make_complex(&real, &imag, NULL, - imp->location()); - mpfr_clear(real); - mpfr_clear(imag); - return ret; - } - else if (num.find('.') == std::string::npos - && num.find('E') == std::string::npos) - { - bool is_character_constant = (!num.empty() - && num[num.length() - 1] == '\''); - if (is_character_constant) - num = num.substr(0, num.length() - 1); - mpz_t val; - if (mpz_init_set_str(val, num.c_str(), 10) != 0) - { - error_at(imp->location(), "bad number in import data: %qs", - num.c_str()); - return Expression::make_error(imp->location()); - } - Expression* ret; - if (is_character_constant) - ret = Expression::make_character(&val, NULL, imp->location()); - else - ret = Expression::make_integer(&val, NULL, imp->location()); - mpz_clear(val); - return ret; - } - else - { - mpfr_t val; - if (mpfr_init_set_str(val, num.c_str(), 10, GMP_RNDN) != 0) - { - error_at(imp->location(), "bad number in import data: %qs", - num.c_str()); - return Expression::make_error(imp->location()); - } - Expression* ret = Expression::make_float(&val, NULL, imp->location()); - mpfr_clear(val); - return ret; - } -} -// Ast dump for integer expression. - -void -Integer_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const -{ - if (this->is_character_constant_) - ast_dump_context->ostream() << '\''; - Integer_expression::export_integer(ast_dump_context, this->val_); - if (this->is_character_constant_) - ast_dump_context->ostream() << '\''; -} - -// Build a new integer value. - -Expression* -Expression::make_integer(const mpz_t* val, Type* type, Location location) -{ - return new Integer_expression(val, type, false, location); -} - -// Build a new character constant value. - -Expression* -Expression::make_character(const mpz_t* val, Type* type, Location location) -{ - return new Integer_expression(val, type, true, location); -} - -// Floats. - -class Float_expression : public Expression -{ - public: - Float_expression(const mpfr_t* val, Type* type, Location location) - : Expression(EXPRESSION_FLOAT, location), - type_(type) - { - mpfr_init_set(this->val_, *val, GMP_RNDN); - } - - // Write VAL to export data. - static void - export_float(String_dump* exp, const mpfr_t val); - - // Write VAL to dump file. - static void - dump_float(Ast_dump_context* ast_dump_context, const mpfr_t val); - - protected: - bool - do_is_constant() const - { return true; } - - bool - do_numeric_constant_value(Numeric_constant* nc) const - { - nc->set_float(this->type_, this->val_); - return true; - } - - Type* - do_type(); - - void - do_determine_type(const Type_context*); - - void - do_check_types(Gogo*); - - Expression* - do_copy() - { return Expression::make_float(&this->val_, this->type_, - this->location()); } - - tree - do_get_tree(Translate_context*); - - void - do_export(Export*) const; - - void - do_dump_expression(Ast_dump_context*) const; - - private: - // The floating point value. - mpfr_t val_; - // The type so far. - Type* type_; -}; - -// Return the current type. If we haven't set the type yet, we return -// an abstract float type. - -Type* -Float_expression::do_type() -{ - if (this->type_ == NULL) - this->type_ = Type::make_abstract_float_type(); - return this->type_; -} - -// Set the type of the float value. Here we may switch from an -// abstract type to a real type. - -void -Float_expression::do_determine_type(const Type_context* context) -{ - if (this->type_ != NULL && !this->type_->is_abstract()) - ; - else if (context->type != NULL - && (context->type->integer_type() != NULL - || context->type->float_type() != NULL - || context->type->complex_type() != NULL)) - this->type_ = context->type; - else if (!context->may_be_abstract) - this->type_ = Type::lookup_float_type("float64"); -} - -// Check the type of a float value. - -void -Float_expression::do_check_types(Gogo*) -{ - Type* type = this->type_; - if (type == NULL) - return; - Numeric_constant nc; - nc.set_float(NULL, this->val_); - if (!nc.set_type(this->type_, true, this->location())) - this->set_is_error(); -} - -// Get a tree for a float constant. - -tree -Float_expression::do_get_tree(Translate_context* context) -{ - Gogo* gogo = context->gogo(); - tree type; - if (this->type_ != NULL && !this->type_->is_abstract()) - type = type_to_tree(this->type_->get_backend(gogo)); - else if (this->type_ != NULL && this->type_->integer_type() != NULL) - { - // We have an abstract integer type. We just hope for the best. - type = type_to_tree(Type::lookup_integer_type("int")->get_backend(gogo)); - } - else - { - // If we still have an abstract type here, then this is being - // used in a constant expression which didn't get reduced. We - // just use float64 and hope for the best. - Type* ft = Type::lookup_float_type("float64"); - type = type_to_tree(ft->get_backend(gogo)); - } - return Expression::float_constant_tree(this->val_, type); -} - -// Write a floating point number to a string dump. - -void -Float_expression::export_float(String_dump *exp, const mpfr_t val) -{ - mp_exp_t exponent; - char* s = mpfr_get_str(NULL, &exponent, 10, 0, val, GMP_RNDN); - if (*s == '-') - exp->write_c_string("-"); - exp->write_c_string("0."); - exp->write_c_string(*s == '-' ? s + 1 : s); - mpfr_free_str(s); - char buf[30]; - snprintf(buf, sizeof buf, "E%ld", exponent); - exp->write_c_string(buf); -} - -// Export a floating point number in a constant expression. - -void -Float_expression::do_export(Export* exp) const -{ - Float_expression::export_float(exp, this->val_); - // A trailing space lets us reliably identify the end of the number. - exp->write_c_string(" "); -} - -// Dump a floating point number to the dump file. - -void -Float_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const -{ - Float_expression::export_float(ast_dump_context, this->val_); -} - -// Make a float expression. - -Expression* -Expression::make_float(const mpfr_t* val, Type* type, Location location) -{ - return new Float_expression(val, type, location); -} - -// Complex numbers. - -class Complex_expression : public Expression -{ - public: - Complex_expression(const mpfr_t* real, const mpfr_t* imag, Type* type, - Location location) - : Expression(EXPRESSION_COMPLEX, location), - type_(type) - { - mpfr_init_set(this->real_, *real, GMP_RNDN); - mpfr_init_set(this->imag_, *imag, GMP_RNDN); - } - - // Write REAL/IMAG to string dump. - static void - export_complex(String_dump* exp, const mpfr_t real, const mpfr_t val); - - // Write REAL/IMAG to dump context. - static void - dump_complex(Ast_dump_context* ast_dump_context, - const mpfr_t real, const mpfr_t val); - - protected: - bool - do_is_constant() const - { return true; } - - bool - do_numeric_constant_value(Numeric_constant* nc) const - { - nc->set_complex(this->type_, this->real_, this->imag_); - return true; - } - - Type* - do_type(); - - void - do_determine_type(const Type_context*); - - void - do_check_types(Gogo*); - - Expression* - do_copy() - { - return Expression::make_complex(&this->real_, &this->imag_, this->type_, - this->location()); - } - - tree - do_get_tree(Translate_context*); - - void - do_export(Export*) const; - - void - do_dump_expression(Ast_dump_context*) const; - - private: - // The real part. - mpfr_t real_; - // The imaginary part; - mpfr_t imag_; - // The type if known. - Type* type_; -}; - -// Return the current type. If we haven't set the type yet, we return -// an abstract complex type. - -Type* -Complex_expression::do_type() -{ - if (this->type_ == NULL) - this->type_ = Type::make_abstract_complex_type(); - return this->type_; -} - -// Set the type of the complex value. Here we may switch from an -// abstract type to a real type. - -void -Complex_expression::do_determine_type(const Type_context* context) -{ - if (this->type_ != NULL && !this->type_->is_abstract()) - ; - else if (context->type != NULL - && context->type->complex_type() != NULL) - this->type_ = context->type; - else if (!context->may_be_abstract) - this->type_ = Type::lookup_complex_type("complex128"); -} - -// Check the type of a complex value. - -void -Complex_expression::do_check_types(Gogo*) -{ - Type* type = this->type_; - if (type == NULL) - return; - Numeric_constant nc; - nc.set_complex(NULL, this->real_, this->imag_); - if (!nc.set_type(this->type_, true, this->location())) - this->set_is_error(); -} - -// Get a tree for a complex constant. - -tree -Complex_expression::do_get_tree(Translate_context* context) -{ - Gogo* gogo = context->gogo(); - tree type; - if (this->type_ != NULL && !this->type_->is_abstract()) - type = type_to_tree(this->type_->get_backend(gogo)); - else - { - // If we still have an abstract type here, this this is being - // used in a constant expression which didn't get reduced. We - // just use complex128 and hope for the best. - Type* ct = Type::lookup_complex_type("complex128"); - type = type_to_tree(ct->get_backend(gogo)); - } - return Expression::complex_constant_tree(this->real_, this->imag_, type); -} - -// Write REAL/IMAG to export data. - -void -Complex_expression::export_complex(String_dump* exp, const mpfr_t real, - const mpfr_t imag) -{ - if (!mpfr_zero_p(real)) - { - Float_expression::export_float(exp, real); - if (mpfr_sgn(imag) > 0) - exp->write_c_string("+"); - } - Float_expression::export_float(exp, imag); - exp->write_c_string("i"); -} - -// Export a complex number in a constant expression. - -void -Complex_expression::do_export(Export* exp) const -{ - Complex_expression::export_complex(exp, this->real_, this->imag_); - // A trailing space lets us reliably identify the end of the number. - exp->write_c_string(" "); -} - -// Dump a complex expression to the dump file. - -void -Complex_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const -{ - Complex_expression::export_complex(ast_dump_context, - this->real_, - this->imag_); -} - -// Make a complex expression. - -Expression* -Expression::make_complex(const mpfr_t* real, const mpfr_t* imag, Type* type, - Location location) -{ - return new Complex_expression(real, imag, type, location); -} - -// Find a named object in an expression. - -class Find_named_object : public Traverse -{ - public: - Find_named_object(Named_object* no) - : Traverse(traverse_expressions), - no_(no), found_(false) - { } - - // Whether we found the object. - bool - found() const - { return this->found_; } - - protected: - int - expression(Expression**); - - private: - // The object we are looking for. - Named_object* no_; - // Whether we found it. - bool found_; -}; - -// A reference to a const in an expression. - -class Const_expression : public Expression -{ - public: - Const_expression(Named_object* constant, Location location) - : Expression(EXPRESSION_CONST_REFERENCE, location), - constant_(constant), type_(NULL), seen_(false) - { } - - Named_object* - named_object() - { return this->constant_; } - - // Check that the initializer does not refer to the constant itself. - void - check_for_init_loop(); - - protected: - int - do_traverse(Traverse*); - - Expression* - do_lower(Gogo*, Named_object*, Statement_inserter*, int); - - bool - do_is_constant() const - { return true; } - - bool - do_numeric_constant_value(Numeric_constant* nc) const; - - bool - do_string_constant_value(std::string* val) const; - - Type* - do_type(); - - // The type of a const is set by the declaration, not the use. - void - do_determine_type(const Type_context*); - - void - do_check_types(Gogo*); - - Expression* - do_copy() - { return this; } - - tree - do_get_tree(Translate_context* context); - - // When exporting a reference to a const as part of a const - // expression, we export the value. We ignore the fact that it has - // a name. - void - do_export(Export* exp) const - { this->constant_->const_value()->expr()->export_expression(exp); } - - void - do_dump_expression(Ast_dump_context*) const; - - private: - // The constant. - Named_object* constant_; - // The type of this reference. This is used if the constant has an - // abstract type. - Type* type_; - // Used to prevent infinite recursion when a constant incorrectly - // refers to itself. - mutable bool seen_; -}; - -// Traversal. - -int -Const_expression::do_traverse(Traverse* traverse) -{ - if (this->type_ != NULL) - return Type::traverse(this->type_, traverse); - return TRAVERSE_CONTINUE; -} - -// Lower a constant expression. This is where we convert the -// predeclared constant iota into an integer value. - -Expression* -Const_expression::do_lower(Gogo* gogo, Named_object*, - Statement_inserter*, int iota_value) -{ - if (this->constant_->const_value()->expr()->classification() - == EXPRESSION_IOTA) - { - if (iota_value == -1) - { - error_at(this->location(), - "iota is only defined in const declarations"); - iota_value = 0; - } - mpz_t val; - mpz_init_set_ui(val, static_cast<unsigned long>(iota_value)); - Expression* ret = Expression::make_integer(&val, NULL, - this->location()); - mpz_clear(val); - return ret; - } - - // Make sure that the constant itself has been lowered. - gogo->lower_constant(this->constant_); - - return this; -} - -// Return a numeric constant value. - -bool -Const_expression::do_numeric_constant_value(Numeric_constant* nc) const -{ - if (this->seen_) - return false; - - Expression* e = this->constant_->const_value()->expr(); - - this->seen_ = true; - - bool r = e->numeric_constant_value(nc); - - this->seen_ = false; - - Type* ctype; - if (this->type_ != NULL) - ctype = this->type_; - else - ctype = this->constant_->const_value()->type(); - if (r && ctype != NULL) - { - if (!nc->set_type(ctype, false, this->location())) - return false; - } - - return r; -} - -bool -Const_expression::do_string_constant_value(std::string* val) const -{ - if (this->seen_) - return false; - - Expression* e = this->constant_->const_value()->expr(); - - this->seen_ = true; - bool ok = e->string_constant_value(val); - this->seen_ = false; - - return ok; -} - -// Return the type of the const reference. - -Type* -Const_expression::do_type() -{ - if (this->type_ != NULL) - return this->type_; - - Named_constant* nc = this->constant_->const_value(); - - if (this->seen_ || nc->lowering()) - { - this->report_error(_("constant refers to itself")); - this->type_ = Type::make_error_type(); - return this->type_; - } - - this->seen_ = true; - - Type* ret = nc->type(); - - if (ret != NULL) - { - this->seen_ = false; - return ret; - } - - // During parsing, a named constant may have a NULL type, but we - // must not return a NULL type here. - ret = nc->expr()->type(); - - this->seen_ = false; - - return ret; -} - -// Set the type of the const reference. - -void -Const_expression::do_determine_type(const Type_context* context) -{ - Type* ctype = this->constant_->const_value()->type(); - Type* cetype = (ctype != NULL - ? ctype - : this->constant_->const_value()->expr()->type()); - if (ctype != NULL && !ctype->is_abstract()) - ; - else if (context->type != NULL - && context->type->is_numeric_type() - && cetype->is_numeric_type()) - this->type_ = context->type; - else if (context->type != NULL - && context->type->is_string_type() - && cetype->is_string_type()) - this->type_ = context->type; - else if (context->type != NULL - && context->type->is_boolean_type() - && cetype->is_boolean_type()) - this->type_ = context->type; - else if (!context->may_be_abstract) - { - if (cetype->is_abstract()) - cetype = cetype->make_non_abstract_type(); - this->type_ = cetype; - } -} - -// Check for a loop in which the initializer of a constant refers to -// the constant itself. - -void -Const_expression::check_for_init_loop() -{ - if (this->type_ != NULL && this->type_->is_error()) - return; - - if (this->seen_) - { - this->report_error(_("constant refers to itself")); - this->type_ = Type::make_error_type(); - return; - } - - Expression* init = this->constant_->const_value()->expr(); - Find_named_object find_named_object(this->constant_); - - this->seen_ = true; - Expression::traverse(&init, &find_named_object); - this->seen_ = false; - - if (find_named_object.found()) - { - if (this->type_ == NULL || !this->type_->is_error()) - { - this->report_error(_("constant refers to itself")); - this->type_ = Type::make_error_type(); - } - return; - } -} - -// Check types of a const reference. - -void -Const_expression::do_check_types(Gogo*) -{ - if (this->type_ != NULL && this->type_->is_error()) - return; - - this->check_for_init_loop(); - - // Check that numeric constant fits in type. - if (this->type_ != NULL && this->type_->is_numeric_type()) - { - Numeric_constant nc; - if (this->constant_->const_value()->expr()->numeric_constant_value(&nc)) - { - if (!nc.set_type(this->type_, true, this->location())) - this->set_is_error(); - } - } -} - -// Return a tree for the const reference. - -tree -Const_expression::do_get_tree(Translate_context* context) -{ - Gogo* gogo = context->gogo(); - tree type_tree; - if (this->type_ == NULL) - type_tree = NULL_TREE; - else - { - type_tree = type_to_tree(this->type_->get_backend(gogo)); - if (type_tree == error_mark_node) - return error_mark_node; - } - - // If the type has been set for this expression, but the underlying - // object is an abstract int or float, we try to get the abstract - // value. Otherwise we may lose something in the conversion. - if (this->type_ != NULL - && this->type_->is_numeric_type() - && (this->constant_->const_value()->type() == NULL - || this->constant_->const_value()->type()->is_abstract())) - { - Expression* expr = this->constant_->const_value()->expr(); - Numeric_constant nc; - if (expr->numeric_constant_value(&nc) - && nc.set_type(this->type_, false, this->location())) - { - Expression* e = nc.expression(this->location()); - return e->get_tree(context); - } - } - - tree const_tree = this->constant_->get_tree(gogo, context->function()); - if (this->type_ == NULL - || const_tree == error_mark_node - || TREE_TYPE(const_tree) == error_mark_node) - return const_tree; - - tree ret; - if (TYPE_MAIN_VARIANT(type_tree) == TYPE_MAIN_VARIANT(TREE_TYPE(const_tree))) - ret = fold_convert(type_tree, const_tree); - else if (TREE_CODE(type_tree) == INTEGER_TYPE) - ret = fold(convert_to_integer(type_tree, const_tree)); - else if (TREE_CODE(type_tree) == REAL_TYPE) - ret = fold(convert_to_real(type_tree, const_tree)); - else if (TREE_CODE(type_tree) == COMPLEX_TYPE) - ret = fold(convert_to_complex(type_tree, const_tree)); - else - go_unreachable(); - return ret; -} - -// Dump ast representation for constant expression. - -void -Const_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const -{ - ast_dump_context->ostream() << this->constant_->name(); -} - -// Make a reference to a constant in an expression. - -Expression* -Expression::make_const_reference(Named_object* constant, - Location location) -{ - return new Const_expression(constant, location); -} - -// Find a named object in an expression. - -int -Find_named_object::expression(Expression** pexpr) -{ - switch ((*pexpr)->classification()) - { - case Expression::EXPRESSION_CONST_REFERENCE: - { - Const_expression* ce = static_cast<Const_expression*>(*pexpr); - if (ce->named_object() == this->no_) - break; - - // We need to check a constant initializer explicitly, as - // loops here will not be caught by the loop checking for - // variable initializers. - ce->check_for_init_loop(); - - return TRAVERSE_CONTINUE; - } - - case Expression::EXPRESSION_VAR_REFERENCE: - if ((*pexpr)->var_expression()->named_object() == this->no_) - break; - return TRAVERSE_CONTINUE; - case Expression::EXPRESSION_FUNC_REFERENCE: - if ((*pexpr)->func_expression()->named_object() == this->no_) - break; - return TRAVERSE_CONTINUE; - default: - return TRAVERSE_CONTINUE; - } - this->found_ = true; - return TRAVERSE_EXIT; -} - -// The nil value. - -class Nil_expression : public Expression -{ - public: - Nil_expression(Location location) - : Expression(EXPRESSION_NIL, location) - { } - - static Expression* - do_import(Import*); - - protected: - bool - do_is_constant() const - { return true; } - - Type* - do_type() - { return Type::make_nil_type(); } - - void - do_determine_type(const Type_context*) - { } - - Expression* - do_copy() - { return this; } - - tree - do_get_tree(Translate_context*) - { return null_pointer_node; } - - void - do_export(Export* exp) const - { exp->write_c_string("nil"); } - - void - do_dump_expression(Ast_dump_context* ast_dump_context) const - { ast_dump_context->ostream() << "nil"; } -}; - -// Import a nil expression. - -Expression* -Nil_expression::do_import(Import* imp) -{ - imp->require_c_string("nil"); - return Expression::make_nil(imp->location()); -} - -// Make a nil expression. - -Expression* -Expression::make_nil(Location location) -{ - return new Nil_expression(location); -} - -// The value of the predeclared constant iota. This is little more -// than a marker. This will be lowered to an integer in -// Const_expression::do_lower, which is where we know the value that -// it should have. - -class Iota_expression : public Parser_expression -{ - public: - Iota_expression(Location location) - : Parser_expression(EXPRESSION_IOTA, location) - { } - - protected: - Expression* - do_lower(Gogo*, Named_object*, Statement_inserter*, int) - { go_unreachable(); } - - // There should only ever be one of these. - Expression* - do_copy() - { go_unreachable(); } - - void - do_dump_expression(Ast_dump_context* ast_dump_context) const - { ast_dump_context->ostream() << "iota"; } -}; - -// Make an iota expression. This is only called for one case: the -// value of the predeclared constant iota. - -Expression* -Expression::make_iota() -{ - static Iota_expression iota_expression(Linemap::unknown_location()); - return &iota_expression; -} - -// A type conversion expression. - -class Type_conversion_expression : public Expression -{ - public: - Type_conversion_expression(Type* type, Expression* expr, - Location location) - : Expression(EXPRESSION_CONVERSION, location), - type_(type), expr_(expr), may_convert_function_types_(false) - { } - - // Return the type to which we are converting. - Type* - type() const - { return this->type_; } - - // Return the expression which we are converting. - Expression* - expr() const - { return this->expr_; } - - // Permit converting from one function type to another. This is - // used internally for method expressions. - void - set_may_convert_function_types() - { - this->may_convert_function_types_ = true; - } - - // Import a type conversion expression. - static Expression* - do_import(Import*); - - protected: - int - do_traverse(Traverse* traverse); - - Expression* - do_lower(Gogo*, Named_object*, Statement_inserter*, int); - - bool - do_is_constant() const - { return this->expr_->is_constant(); } - - bool - do_numeric_constant_value(Numeric_constant*) const; - - bool - do_string_constant_value(std::string*) const; - - Type* - do_type() - { return this->type_; } - - void - do_determine_type(const Type_context*) - { - Type_context subcontext(this->type_, false); - this->expr_->determine_type(&subcontext); - } - - void - do_check_types(Gogo*); - - Expression* - do_copy() - { - return new Type_conversion_expression(this->type_, this->expr_->copy(), - this->location()); - } - - tree - do_get_tree(Translate_context* context); - - void - do_export(Export*) const; - - void - do_dump_expression(Ast_dump_context*) const; - - private: - // The type to convert to. - Type* type_; - // The expression to convert. - Expression* expr_; - // True if this is permitted to convert function types. This is - // used internally for method expressions. - bool may_convert_function_types_; -}; - -// Traversal. - -int -Type_conversion_expression::do_traverse(Traverse* traverse) -{ - if (Expression::traverse(&this->expr_, traverse) == TRAVERSE_EXIT - || Type::traverse(this->type_, traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - return TRAVERSE_CONTINUE; -} - -// Convert to a constant at lowering time. - -Expression* -Type_conversion_expression::do_lower(Gogo*, Named_object*, - Statement_inserter*, int) -{ - Type* type = this->type_; - Expression* val = this->expr_; - Location location = this->location(); - - if (type->is_numeric_type()) - { - Numeric_constant nc; - if (val->numeric_constant_value(&nc)) - { - if (!nc.set_type(type, true, location)) - return Expression::make_error(location); - return nc.expression(location); - } - } - - if (type->is_slice_type()) - { - Type* element_type = type->array_type()->element_type()->forwarded(); - bool is_byte = (element_type->integer_type() != NULL - && element_type->integer_type()->is_byte()); - bool is_rune = (element_type->integer_type() != NULL - && element_type->integer_type()->is_rune()); - if (is_byte || is_rune) - { - std::string s; - if (val->string_constant_value(&s)) - { - Expression_list* vals = new Expression_list(); - if (is_byte) - { - for (std::string::const_iterator p = s.begin(); - p != s.end(); - p++) - { - mpz_t val; - mpz_init_set_ui(val, static_cast<unsigned char>(*p)); - Expression* v = Expression::make_integer(&val, - element_type, - location); - vals->push_back(v); - mpz_clear(val); - } - } - else - { - const char *p = s.data(); - const char *pend = s.data() + s.length(); - while (p < pend) - { - unsigned int c; - int adv = Lex::fetch_char(p, &c); - if (adv == 0) - { - warning_at(this->location(), 0, - "invalid UTF-8 encoding"); - adv = 1; - } - p += adv; - mpz_t val; - mpz_init_set_ui(val, c); - Expression* v = Expression::make_integer(&val, - element_type, - location); - vals->push_back(v); - mpz_clear(val); - } - } - - return Expression::make_slice_composite_literal(type, vals, - location); - } - } - } - - return this; -} - -// Return the constant numeric value if there is one. - -bool -Type_conversion_expression::do_numeric_constant_value( - Numeric_constant* nc) const -{ - if (!this->type_->is_numeric_type()) - return false; - if (!this->expr_->numeric_constant_value(nc)) - return false; - return nc->set_type(this->type_, false, this->location()); -} - -// Return the constant string value if there is one. - -bool -Type_conversion_expression::do_string_constant_value(std::string* val) const -{ - if (this->type_->is_string_type() - && this->expr_->type()->integer_type() != NULL) - { - Numeric_constant nc; - if (this->expr_->numeric_constant_value(&nc)) - { - unsigned long ival; - if (nc.to_unsigned_long(&ival) == Numeric_constant::NC_UL_VALID) - { - val->clear(); - Lex::append_char(ival, true, val, this->location()); - return true; - } - } - } - - // FIXME: Could handle conversion from const []int here. - - return false; -} - -// Check that types are convertible. - -void -Type_conversion_expression::do_check_types(Gogo*) -{ - Type* type = this->type_; - Type* expr_type = this->expr_->type(); - std::string reason; - - if (type->is_error() || expr_type->is_error()) - { - this->set_is_error(); - return; - } - - if (this->may_convert_function_types_ - && type->function_type() != NULL - && expr_type->function_type() != NULL) - return; - - if (Type::are_convertible(type, expr_type, &reason)) - return; - - error_at(this->location(), "%s", reason.c_str()); - this->set_is_error(); -} - -// Get a tree for a type conversion. - -tree -Type_conversion_expression::do_get_tree(Translate_context* context) -{ - Gogo* gogo = context->gogo(); - tree type_tree = type_to_tree(this->type_->get_backend(gogo)); - tree expr_tree = this->expr_->get_tree(context); - - if (type_tree == error_mark_node - || expr_tree == error_mark_node - || TREE_TYPE(expr_tree) == error_mark_node) - return error_mark_node; - - if (TYPE_MAIN_VARIANT(type_tree) == TYPE_MAIN_VARIANT(TREE_TYPE(expr_tree))) - return fold_convert(type_tree, expr_tree); - - Type* type = this->type_; - Type* expr_type = this->expr_->type(); - tree ret; - if (type->interface_type() != NULL || expr_type->interface_type() != NULL) - ret = Expression::convert_for_assignment(context, type, expr_type, - expr_tree, this->location()); - else if (type->integer_type() != NULL) - { - if (expr_type->integer_type() != NULL - || expr_type->float_type() != NULL - || expr_type->is_unsafe_pointer_type()) - ret = fold(convert_to_integer(type_tree, expr_tree)); - else - go_unreachable(); - } - else if (type->float_type() != NULL) - { - if (expr_type->integer_type() != NULL - || expr_type->float_type() != NULL) - ret = fold(convert_to_real(type_tree, expr_tree)); - else - go_unreachable(); - } - else if (type->complex_type() != NULL) - { - if (expr_type->complex_type() != NULL) - ret = fold(convert_to_complex(type_tree, expr_tree)); - else - go_unreachable(); - } - else if (type->is_string_type() - && expr_type->integer_type() != NULL) - { - Type* int_type = Type::lookup_integer_type("int"); - tree int_type_tree = type_to_tree(int_type->get_backend(gogo)); - - expr_tree = fold_convert(int_type_tree, expr_tree); - if (host_integerp(expr_tree, 0)) - { - HOST_WIDE_INT intval = tree_low_cst(expr_tree, 0); - std::string s; - Lex::append_char(intval, true, &s, this->location()); - Expression* se = Expression::make_string(s, this->location()); - return se->get_tree(context); - } - - static tree int_to_string_fndecl; - ret = Gogo::call_builtin(&int_to_string_fndecl, - this->location(), - "__go_int_to_string", - 1, - type_tree, - int_type_tree, - expr_tree); - } - else if (type->is_string_type() && expr_type->is_slice_type()) - { - if (!DECL_P(expr_tree)) - expr_tree = save_expr(expr_tree); - - Type* int_type = Type::lookup_integer_type("int"); - tree int_type_tree = type_to_tree(int_type->get_backend(gogo)); - - Array_type* a = expr_type->array_type(); - Type* e = a->element_type()->forwarded(); - go_assert(e->integer_type() != NULL); - tree valptr = fold_convert(const_ptr_type_node, - a->value_pointer_tree(gogo, expr_tree)); - tree len = a->length_tree(gogo, expr_tree); - len = fold_convert_loc(this->location().gcc_location(), int_type_tree, - len); - if (e->integer_type()->is_byte()) - { - static tree byte_array_to_string_fndecl; - ret = Gogo::call_builtin(&byte_array_to_string_fndecl, - this->location(), - "__go_byte_array_to_string", - 2, - type_tree, - const_ptr_type_node, - valptr, - int_type_tree, - len); - } - else - { - go_assert(e->integer_type()->is_rune()); - static tree int_array_to_string_fndecl; - ret = Gogo::call_builtin(&int_array_to_string_fndecl, - this->location(), - "__go_int_array_to_string", - 2, - type_tree, - const_ptr_type_node, - valptr, - int_type_tree, - len); - } - } - else if (type->is_slice_type() && expr_type->is_string_type()) - { - Type* e = type->array_type()->element_type()->forwarded(); - go_assert(e->integer_type() != NULL); - if (e->integer_type()->is_byte()) - { - tree string_to_byte_array_fndecl = NULL_TREE; - ret = Gogo::call_builtin(&string_to_byte_array_fndecl, - this->location(), - "__go_string_to_byte_array", - 1, - type_tree, - TREE_TYPE(expr_tree), - expr_tree); - } - else - { - go_assert(e->integer_type()->is_rune()); - tree string_to_int_array_fndecl = NULL_TREE; - ret = Gogo::call_builtin(&string_to_int_array_fndecl, - this->location(), - "__go_string_to_int_array", - 1, - type_tree, - TREE_TYPE(expr_tree), - expr_tree); - } - } - else if ((type->is_unsafe_pointer_type() - && expr_type->points_to() != NULL) - || (expr_type->is_unsafe_pointer_type() - && type->points_to() != NULL)) - ret = fold_convert(type_tree, expr_tree); - else if (type->is_unsafe_pointer_type() - && expr_type->integer_type() != NULL) - ret = convert_to_pointer(type_tree, expr_tree); - else if (this->may_convert_function_types_ - && type->function_type() != NULL - && expr_type->function_type() != NULL) - ret = fold_convert_loc(this->location().gcc_location(), type_tree, - expr_tree); - else - ret = Expression::convert_for_assignment(context, type, expr_type, - expr_tree, this->location()); - - return ret; -} - -// Output a type conversion in a constant expression. - -void -Type_conversion_expression::do_export(Export* exp) const -{ - exp->write_c_string("convert("); - exp->write_type(this->type_); - exp->write_c_string(", "); - this->expr_->export_expression(exp); - exp->write_c_string(")"); -} - -// Import a type conversion or a struct construction. - -Expression* -Type_conversion_expression::do_import(Import* imp) -{ - imp->require_c_string("convert("); - Type* type = imp->read_type(); - imp->require_c_string(", "); - Expression* val = Expression::import_expression(imp); - imp->require_c_string(")"); - return Expression::make_cast(type, val, imp->location()); -} - -// Dump ast representation for a type conversion expression. - -void -Type_conversion_expression::do_dump_expression( - Ast_dump_context* ast_dump_context) const -{ - ast_dump_context->dump_type(this->type_); - ast_dump_context->ostream() << "("; - ast_dump_context->dump_expression(this->expr_); - ast_dump_context->ostream() << ") "; -} - -// Make a type cast expression. - -Expression* -Expression::make_cast(Type* type, Expression* val, Location location) -{ - if (type->is_error_type() || val->is_error_expression()) - return Expression::make_error(location); - return new Type_conversion_expression(type, val, location); -} - -// An unsafe type conversion, used to pass values to builtin functions. - -class Unsafe_type_conversion_expression : public Expression -{ - public: - Unsafe_type_conversion_expression(Type* type, Expression* expr, - Location location) - : Expression(EXPRESSION_UNSAFE_CONVERSION, location), - type_(type), expr_(expr) - { } - - protected: - int - do_traverse(Traverse* traverse); - - Type* - do_type() - { return this->type_; } - - void - do_determine_type(const Type_context*) - { this->expr_->determine_type_no_context(); } - - Expression* - do_copy() - { - return new Unsafe_type_conversion_expression(this->type_, - this->expr_->copy(), - this->location()); - } - - tree - do_get_tree(Translate_context*); - - void - do_dump_expression(Ast_dump_context*) const; - - private: - // The type to convert to. - Type* type_; - // The expression to convert. - Expression* expr_; -}; - -// Traversal. - -int -Unsafe_type_conversion_expression::do_traverse(Traverse* traverse) -{ - if (Expression::traverse(&this->expr_, traverse) == TRAVERSE_EXIT - || Type::traverse(this->type_, traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - return TRAVERSE_CONTINUE; -} - -// Convert to backend representation. - -tree -Unsafe_type_conversion_expression::do_get_tree(Translate_context* context) -{ - // We are only called for a limited number of cases. - - Type* t = this->type_; - Type* et = this->expr_->type(); - - tree type_tree = type_to_tree(this->type_->get_backend(context->gogo())); - tree expr_tree = this->expr_->get_tree(context); - if (type_tree == error_mark_node || expr_tree == error_mark_node) - return error_mark_node; - - Location loc = this->location(); - - bool use_view_convert = false; - if (t->is_slice_type()) - { - go_assert(et->is_slice_type()); - use_view_convert = true; - } - else if (t->map_type() != NULL) - go_assert(et->map_type() != NULL); - else if (t->channel_type() != NULL) - go_assert(et->channel_type() != NULL); - else if (t->points_to() != NULL) - go_assert(et->points_to() != NULL || et->is_nil_type()); - else if (et->is_unsafe_pointer_type()) - go_assert(t->points_to() != NULL); - else if (t->interface_type() != NULL && !t->interface_type()->is_empty()) - { - go_assert(et->interface_type() != NULL - && !et->interface_type()->is_empty()); - use_view_convert = true; - } - else if (t->interface_type() != NULL && t->interface_type()->is_empty()) - { - go_assert(et->interface_type() != NULL - && et->interface_type()->is_empty()); - use_view_convert = true; - } - else if (t->integer_type() != NULL) - { - go_assert(et->is_boolean_type() - || et->integer_type() != NULL - || et->function_type() != NULL - || et->points_to() != NULL - || et->map_type() != NULL - || et->channel_type() != NULL); - return convert_to_integer(type_tree, expr_tree); - } - else - go_unreachable(); - - if (use_view_convert) - return fold_build1_loc(loc.gcc_location(), VIEW_CONVERT_EXPR, type_tree, - expr_tree); - else - return fold_convert_loc(loc.gcc_location(), type_tree, expr_tree); -} - -// Dump ast representation for an unsafe type conversion expression. - -void -Unsafe_type_conversion_expression::do_dump_expression( - Ast_dump_context* ast_dump_context) const -{ - ast_dump_context->dump_type(this->type_); - ast_dump_context->ostream() << "("; - ast_dump_context->dump_expression(this->expr_); - ast_dump_context->ostream() << ") "; -} - -// Make an unsafe type conversion expression. - -Expression* -Expression::make_unsafe_cast(Type* type, Expression* expr, - Location location) -{ - return new Unsafe_type_conversion_expression(type, expr, location); -} - -// Unary expressions. - -class Unary_expression : public Expression -{ - public: - Unary_expression(Operator op, Expression* expr, Location location) - : Expression(EXPRESSION_UNARY, location), - op_(op), escapes_(true), create_temp_(false), expr_(expr) - { } - - // Return the operator. - Operator - op() const - { return this->op_; } - - // Return the operand. - Expression* - operand() const - { return this->expr_; } - - // Record that an address expression does not escape. - void - set_does_not_escape() - { - go_assert(this->op_ == OPERATOR_AND); - this->escapes_ = false; - } - - // Record that this is an address expression which should create a - // temporary variable if necessary. This is used for method calls. - void - set_create_temp() - { - go_assert(this->op_ == OPERATOR_AND); - this->create_temp_ = true; - } - - // Apply unary opcode OP to UNC, setting NC. Return true if this - // could be done, false if not. Issue errors for overflow. - static bool - eval_constant(Operator op, const Numeric_constant* unc, - Location, Numeric_constant* nc); - - static Expression* - do_import(Import*); - - protected: - int - do_traverse(Traverse* traverse) - { return Expression::traverse(&this->expr_, traverse); } - - Expression* - do_lower(Gogo*, Named_object*, Statement_inserter*, int); - - bool - do_is_constant() const; - - bool - do_numeric_constant_value(Numeric_constant*) const; - - Type* - do_type(); - - void - do_determine_type(const Type_context*); - - void - do_check_types(Gogo*); - - Expression* - do_copy() - { - return Expression::make_unary(this->op_, this->expr_->copy(), - this->location()); - } - - bool - do_must_eval_subexpressions_in_order(int*) const - { return this->op_ == OPERATOR_MULT; } - - bool - do_is_addressable() const - { return this->op_ == OPERATOR_MULT; } - - tree - do_get_tree(Translate_context*); - - void - do_export(Export*) const; - - void - do_dump_expression(Ast_dump_context*) const; - - private: - // The unary operator to apply. - Operator op_; - // Normally true. False if this is an address expression which does - // not escape the current function. - bool escapes_; - // True if this is an address expression which should create a - // temporary variable if necessary. - bool create_temp_; - // The operand. - Expression* expr_; -}; - -// If we are taking the address of a composite literal, and the -// contents are not constant, then we want to make a heap composite -// instead. - -Expression* -Unary_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int) -{ - Location loc = this->location(); - Operator op = this->op_; - Expression* expr = this->expr_; - - if (op == OPERATOR_MULT && expr->is_type_expression()) - return Expression::make_type(Type::make_pointer_type(expr->type()), loc); - - // *&x simplifies to x. *(*T)(unsafe.Pointer)(&x) does not require - // moving x to the heap. FIXME: Is it worth doing a real escape - // analysis here? This case is found in math/unsafe.go and is - // therefore worth special casing. - if (op == OPERATOR_MULT) - { - Expression* e = expr; - while (e->classification() == EXPRESSION_CONVERSION) - { - Type_conversion_expression* te - = static_cast<Type_conversion_expression*>(e); - e = te->expr(); - } - - if (e->classification() == EXPRESSION_UNARY) - { - Unary_expression* ue = static_cast<Unary_expression*>(e); - if (ue->op_ == OPERATOR_AND) - { - if (e == expr) - { - // *&x == x. - return ue->expr_; - } - ue->set_does_not_escape(); - } - } - } - - // Catching an invalid indirection of unsafe.Pointer here avoid - // having to deal with TYPE_VOID in other places. - if (op == OPERATOR_MULT && expr->type()->is_unsafe_pointer_type()) - { - error_at(this->location(), "invalid indirect of %<unsafe.Pointer%>"); - return Expression::make_error(this->location()); - } - - if (op == OPERATOR_PLUS || op == OPERATOR_MINUS || op == OPERATOR_XOR) - { - Numeric_constant nc; - if (expr->numeric_constant_value(&nc)) - { - Numeric_constant result; - if (Unary_expression::eval_constant(op, &nc, loc, &result)) - return result.expression(loc); - } - } - - return this; -} - -// Return whether a unary expression is a constant. - -bool -Unary_expression::do_is_constant() const -{ - if (this->op_ == OPERATOR_MULT) - { - // Indirecting through a pointer is only constant if the object - // to which the expression points is constant, but we currently - // have no way to determine that. - return false; - } - else if (this->op_ == OPERATOR_AND) - { - // Taking the address of a variable is constant if it is a - // global variable, not constant otherwise. In other cases - // taking the address is probably not a constant. - Var_expression* ve = this->expr_->var_expression(); - if (ve != NULL) - { - Named_object* no = ve->named_object(); - return no->is_variable() && no->var_value()->is_global(); - } - return false; - } - else - return this->expr_->is_constant(); -} - -// Apply unary opcode OP to UNC, setting NC. Return true if this -// could be done, false if not. Issue errors for overflow. - -bool -Unary_expression::eval_constant(Operator op, const Numeric_constant* unc, - Location location, Numeric_constant* nc) -{ - switch (op) - { - case OPERATOR_PLUS: - *nc = *unc; - return true; - - case OPERATOR_MINUS: - if (unc->is_int() || unc->is_rune()) - break; - else if (unc->is_float()) - { - mpfr_t uval; - unc->get_float(&uval); - mpfr_t val; - mpfr_init(val); - mpfr_neg(val, uval, GMP_RNDN); - nc->set_float(unc->type(), val); - mpfr_clear(uval); - mpfr_clear(val); - return true; - } - else if (unc->is_complex()) - { - mpfr_t ureal, uimag; - unc->get_complex(&ureal, &uimag); - mpfr_t real, imag; - mpfr_init(real); - mpfr_init(imag); - mpfr_neg(real, ureal, GMP_RNDN); - mpfr_neg(imag, uimag, GMP_RNDN); - nc->set_complex(unc->type(), real, imag); - mpfr_clear(ureal); - mpfr_clear(uimag); - mpfr_clear(real); - mpfr_clear(imag); - return true; - } - else - go_unreachable(); - - case OPERATOR_XOR: - break; - - case OPERATOR_NOT: - case OPERATOR_AND: - case OPERATOR_MULT: - return false; - - default: - go_unreachable(); - } - - if (!unc->is_int() && !unc->is_rune()) - return false; - - mpz_t uval; - if (unc->is_rune()) - unc->get_rune(&uval); - else - unc->get_int(&uval); - mpz_t val; - mpz_init(val); - - switch (op) - { - case OPERATOR_MINUS: - mpz_neg(val, uval); - break; - - case OPERATOR_NOT: - mpz_set_ui(val, mpz_cmp_si(uval, 0) == 0 ? 1 : 0); - break; - - case OPERATOR_XOR: - { - Type* utype = unc->type(); - if (utype->integer_type() == NULL - || utype->integer_type()->is_abstract()) - mpz_com(val, uval); - else - { - // The number of HOST_WIDE_INTs that it takes to represent - // UVAL. - size_t count = ((mpz_sizeinbase(uval, 2) - + HOST_BITS_PER_WIDE_INT - - 1) - / HOST_BITS_PER_WIDE_INT); - - unsigned HOST_WIDE_INT* phwi = new unsigned HOST_WIDE_INT[count]; - memset(phwi, 0, count * sizeof(HOST_WIDE_INT)); - - size_t obits = utype->integer_type()->bits(); - - if (!utype->integer_type()->is_unsigned() && mpz_sgn(uval) < 0) - { - mpz_t adj; - mpz_init_set_ui(adj, 1); - mpz_mul_2exp(adj, adj, obits); - mpz_add(uval, uval, adj); - mpz_clear(adj); - } - - size_t ecount; - mpz_export(phwi, &ecount, -1, sizeof(HOST_WIDE_INT), 0, 0, uval); - go_assert(ecount <= count); - - // Trim down to the number of words required by the type. - size_t ocount = ((obits + HOST_BITS_PER_WIDE_INT - 1) - / HOST_BITS_PER_WIDE_INT); - go_assert(ocount <= count); - - for (size_t i = 0; i < ocount; ++i) - phwi[i] = ~phwi[i]; - - size_t clearbits = ocount * HOST_BITS_PER_WIDE_INT - obits; - if (clearbits != 0) - phwi[ocount - 1] &= (((unsigned HOST_WIDE_INT) (HOST_WIDE_INT) -1) - >> clearbits); - - mpz_import(val, ocount, -1, sizeof(HOST_WIDE_INT), 0, 0, phwi); - - if (!utype->integer_type()->is_unsigned() - && mpz_tstbit(val, obits - 1)) - { - mpz_t adj; - mpz_init_set_ui(adj, 1); - mpz_mul_2exp(adj, adj, obits); - mpz_sub(val, val, adj); - mpz_clear(adj); - } - - delete[] phwi; - } - } - break; - - default: - go_unreachable(); - } - - if (unc->is_rune()) - nc->set_rune(NULL, val); - else - nc->set_int(NULL, val); - - mpz_clear(uval); - mpz_clear(val); - - return nc->set_type(unc->type(), true, location); -} - -// Return the integral constant value of a unary expression, if it has one. - -bool -Unary_expression::do_numeric_constant_value(Numeric_constant* nc) const -{ - Numeric_constant unc; - if (!this->expr_->numeric_constant_value(&unc)) - return false; - return Unary_expression::eval_constant(this->op_, &unc, this->location(), - nc); -} - -// Return the type of a unary expression. - -Type* -Unary_expression::do_type() -{ - switch (this->op_) - { - case OPERATOR_PLUS: - case OPERATOR_MINUS: - case OPERATOR_NOT: - case OPERATOR_XOR: - return this->expr_->type(); - - case OPERATOR_AND: - return Type::make_pointer_type(this->expr_->type()); - - case OPERATOR_MULT: - { - Type* subtype = this->expr_->type(); - Type* points_to = subtype->points_to(); - if (points_to == NULL) - return Type::make_error_type(); - return points_to; - } - - default: - go_unreachable(); - } -} - -// Determine abstract types for a unary expression. - -void -Unary_expression::do_determine_type(const Type_context* context) -{ - switch (this->op_) - { - case OPERATOR_PLUS: - case OPERATOR_MINUS: - case OPERATOR_NOT: - case OPERATOR_XOR: - this->expr_->determine_type(context); - break; - - case OPERATOR_AND: - // Taking the address of something. - { - Type* subtype = (context->type == NULL - ? NULL - : context->type->points_to()); - Type_context subcontext(subtype, false); - this->expr_->determine_type(&subcontext); - } - break; - - case OPERATOR_MULT: - // Indirecting through a pointer. - { - Type* subtype = (context->type == NULL - ? NULL - : Type::make_pointer_type(context->type)); - Type_context subcontext(subtype, false); - this->expr_->determine_type(&subcontext); - } - break; - - default: - go_unreachable(); - } -} - -// Check types for a unary expression. - -void -Unary_expression::do_check_types(Gogo*) -{ - Type* type = this->expr_->type(); - if (type->is_error()) - { - this->set_is_error(); - return; - } - - switch (this->op_) - { - case OPERATOR_PLUS: - case OPERATOR_MINUS: - if (type->integer_type() == NULL - && type->float_type() == NULL - && type->complex_type() == NULL) - this->report_error(_("expected numeric type")); - break; - - case OPERATOR_NOT: - if (!type->is_boolean_type()) - this->report_error(_("expected boolean type")); - break; - - case OPERATOR_XOR: - if (type->integer_type() == NULL - && !type->is_boolean_type()) - this->report_error(_("expected integer or boolean type")); - break; - - case OPERATOR_AND: - if (!this->expr_->is_addressable()) - { - if (!this->create_temp_) - this->report_error(_("invalid operand for unary %<&%>")); - } - else - this->expr_->address_taken(this->escapes_); - break; - - case OPERATOR_MULT: - // Indirecting through a pointer. - if (type->points_to() == NULL) - this->report_error(_("expected pointer")); - break; - - default: - go_unreachable(); - } -} - -// Get a tree for a unary expression. - -tree -Unary_expression::do_get_tree(Translate_context* context) -{ - Gogo* gogo = context->gogo(); - Location loc = this->location(); - - // Taking the address of a set-and-use-temporary expression requires - // setting the temporary and then taking the address. - if (this->op_ == OPERATOR_AND) - { - Set_and_use_temporary_expression* sut = - this->expr_->set_and_use_temporary_expression(); - if (sut != NULL) - { - Temporary_statement* temp = sut->temporary(); - Bvariable* bvar = temp->get_backend_variable(context); - tree var_tree = var_to_tree(bvar); - Expression* val = sut->expression(); - tree val_tree = val->get_tree(context); - if (var_tree == error_mark_node || val_tree == error_mark_node) - return error_mark_node; - tree addr_tree = build_fold_addr_expr_loc(loc.gcc_location(), - var_tree); - return build2_loc(loc.gcc_location(), COMPOUND_EXPR, - TREE_TYPE(addr_tree), - build2_loc(sut->location().gcc_location(), - MODIFY_EXPR, void_type_node, - var_tree, val_tree), - addr_tree); - } - } - - tree expr = this->expr_->get_tree(context); - if (expr == error_mark_node) - return error_mark_node; - - switch (this->op_) - { - case OPERATOR_PLUS: - return expr; - - case OPERATOR_MINUS: - { - tree type = TREE_TYPE(expr); - tree compute_type = excess_precision_type(type); - if (compute_type != NULL_TREE) - expr = ::convert(compute_type, expr); - tree ret = fold_build1_loc(loc.gcc_location(), NEGATE_EXPR, - (compute_type != NULL_TREE - ? compute_type - : type), - expr); - if (compute_type != NULL_TREE) - ret = ::convert(type, ret); - return ret; - } - - case OPERATOR_NOT: - if (TREE_CODE(TREE_TYPE(expr)) == BOOLEAN_TYPE) - return fold_build1_loc(loc.gcc_location(), TRUTH_NOT_EXPR, - TREE_TYPE(expr), expr); - else - return fold_build2_loc(loc.gcc_location(), NE_EXPR, boolean_type_node, - expr, build_int_cst(TREE_TYPE(expr), 0)); - - case OPERATOR_XOR: - return fold_build1_loc(loc.gcc_location(), BIT_NOT_EXPR, TREE_TYPE(expr), - expr); - - case OPERATOR_AND: - if (!this->create_temp_) - { - // We should not see a non-constant constructor here; cases - // where we would see one should have been moved onto the - // heap at parse time. Taking the address of a nonconstant - // constructor will not do what the programmer expects. - go_assert(TREE_CODE(expr) != CONSTRUCTOR || TREE_CONSTANT(expr)); - go_assert(TREE_CODE(expr) != ADDR_EXPR); - } - - // Build a decl for a constant constructor. - if (TREE_CODE(expr) == CONSTRUCTOR && TREE_CONSTANT(expr)) - { - tree decl = build_decl(this->location().gcc_location(), VAR_DECL, - create_tmp_var_name("C"), TREE_TYPE(expr)); - DECL_EXTERNAL(decl) = 0; - TREE_PUBLIC(decl) = 0; - TREE_READONLY(decl) = 1; - TREE_CONSTANT(decl) = 1; - TREE_STATIC(decl) = 1; - TREE_ADDRESSABLE(decl) = 1; - DECL_ARTIFICIAL(decl) = 1; - DECL_INITIAL(decl) = expr; - rest_of_decl_compilation(decl, 1, 0); - expr = decl; - } - - if (this->create_temp_ - && !TREE_ADDRESSABLE(TREE_TYPE(expr)) - && (TREE_CODE(expr) == CONST_DECL || !DECL_P(expr)) - && TREE_CODE(expr) != INDIRECT_REF - && TREE_CODE(expr) != COMPONENT_REF) - { - if (current_function_decl != NULL) - { - tree tmp = create_tmp_var(TREE_TYPE(expr), get_name(expr)); - DECL_IGNORED_P(tmp) = 1; - DECL_INITIAL(tmp) = expr; - TREE_ADDRESSABLE(tmp) = 1; - return build2_loc(loc.gcc_location(), COMPOUND_EXPR, - build_pointer_type(TREE_TYPE(expr)), - build1_loc(loc.gcc_location(), DECL_EXPR, - void_type_node, tmp), - build_fold_addr_expr_loc(loc.gcc_location(), - tmp)); - } - else - { - tree tmp = build_decl(loc.gcc_location(), VAR_DECL, - create_tmp_var_name("A"), TREE_TYPE(expr)); - DECL_EXTERNAL(tmp) = 0; - TREE_PUBLIC(tmp) = 0; - TREE_STATIC(tmp) = 1; - DECL_ARTIFICIAL(tmp) = 1; - TREE_ADDRESSABLE(tmp) = 1; - tree make_tmp; - if (!TREE_CONSTANT(expr)) - make_tmp = fold_build2_loc(loc.gcc_location(), INIT_EXPR, - void_type_node, tmp, expr); - else - { - TREE_READONLY(tmp) = 1; - TREE_CONSTANT(tmp) = 1; - DECL_INITIAL(tmp) = expr; - make_tmp = NULL_TREE; - } - rest_of_decl_compilation(tmp, 1, 0); - tree addr = build_fold_addr_expr_loc(loc.gcc_location(), tmp); - if (make_tmp == NULL_TREE) - return addr; - return build2_loc(loc.gcc_location(), COMPOUND_EXPR, - TREE_TYPE(addr), make_tmp, addr); - } - } - - return build_fold_addr_expr_loc(loc.gcc_location(), expr); - - case OPERATOR_MULT: - { - go_assert(POINTER_TYPE_P(TREE_TYPE(expr))); - - // If we are dereferencing the pointer to a large struct, we - // need to check for nil. We don't bother to check for small - // structs because we expect the system to crash on a nil - // pointer dereference. - tree target_type_tree = TREE_TYPE(TREE_TYPE(expr)); - if (!VOID_TYPE_P(target_type_tree)) - { - HOST_WIDE_INT s = int_size_in_bytes(target_type_tree); - if (s == -1 || s >= 4096) - { - if (!DECL_P(expr)) - expr = save_expr(expr); - tree compare = fold_build2_loc(loc.gcc_location(), EQ_EXPR, - boolean_type_node, - expr, - fold_convert(TREE_TYPE(expr), - null_pointer_node)); - tree crash = gogo->runtime_error(RUNTIME_ERROR_NIL_DEREFERENCE, - loc); - expr = fold_build2_loc(loc.gcc_location(), COMPOUND_EXPR, - TREE_TYPE(expr), build3(COND_EXPR, - void_type_node, - compare, crash, - NULL_TREE), - expr); - } - } - - // If the type of EXPR is a recursive pointer type, then we - // need to insert a cast before indirecting. - if (VOID_TYPE_P(target_type_tree)) - { - Type* pt = this->expr_->type()->points_to(); - tree ind = type_to_tree(pt->get_backend(gogo)); - expr = fold_convert_loc(loc.gcc_location(), - build_pointer_type(ind), expr); - } - - return build_fold_indirect_ref_loc(loc.gcc_location(), expr); - } - - default: - go_unreachable(); - } -} - -// Export a unary expression. - -void -Unary_expression::do_export(Export* exp) const -{ - switch (this->op_) - { - case OPERATOR_PLUS: - exp->write_c_string("+ "); - break; - case OPERATOR_MINUS: - exp->write_c_string("- "); - break; - case OPERATOR_NOT: - exp->write_c_string("! "); - break; - case OPERATOR_XOR: - exp->write_c_string("^ "); - break; - case OPERATOR_AND: - case OPERATOR_MULT: - default: - go_unreachable(); - } - this->expr_->export_expression(exp); -} - -// Import a unary expression. - -Expression* -Unary_expression::do_import(Import* imp) -{ - Operator op; - switch (imp->get_char()) - { - case '+': - op = OPERATOR_PLUS; - break; - case '-': - op = OPERATOR_MINUS; - break; - case '!': - op = OPERATOR_NOT; - break; - case '^': - op = OPERATOR_XOR; - break; - default: - go_unreachable(); - } - imp->require_c_string(" "); - Expression* expr = Expression::import_expression(imp); - return Expression::make_unary(op, expr, imp->location()); -} - -// Dump ast representation of an unary expression. - -void -Unary_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const -{ - ast_dump_context->dump_operator(this->op_); - ast_dump_context->ostream() << "("; - ast_dump_context->dump_expression(this->expr_); - ast_dump_context->ostream() << ") "; -} - -// Make a unary expression. - -Expression* -Expression::make_unary(Operator op, Expression* expr, Location location) -{ - return new Unary_expression(op, expr, location); -} - -// If this is an indirection through a pointer, return the expression -// being pointed through. Otherwise return this. - -Expression* -Expression::deref() -{ - if (this->classification_ == EXPRESSION_UNARY) - { - Unary_expression* ue = static_cast<Unary_expression*>(this); - if (ue->op() == OPERATOR_MULT) - return ue->operand(); - } - return this; -} - -// Class Binary_expression. - -// Traversal. - -int -Binary_expression::do_traverse(Traverse* traverse) -{ - int t = Expression::traverse(&this->left_, traverse); - if (t == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - return Expression::traverse(&this->right_, traverse); -} - -// Return the type to use for a binary operation on operands of -// LEFT_TYPE and RIGHT_TYPE. These are the types of constants and as -// such may be NULL or abstract. - -bool -Binary_expression::operation_type(Operator op, Type* left_type, - Type* right_type, Type** result_type) -{ - if (left_type != right_type - && !left_type->is_abstract() - && !right_type->is_abstract() - && left_type->base() != right_type->base() - && op != OPERATOR_LSHIFT - && op != OPERATOR_RSHIFT) - { - // May be a type error--let it be diagnosed elsewhere. - return false; - } - - if (op == OPERATOR_LSHIFT || op == OPERATOR_RSHIFT) - { - if (left_type->integer_type() != NULL) - *result_type = left_type; - else - *result_type = Type::make_abstract_integer_type(); - } - else if (!left_type->is_abstract() && left_type->named_type() != NULL) - *result_type = left_type; - else if (!right_type->is_abstract() && right_type->named_type() != NULL) - *result_type = right_type; - else if (!left_type->is_abstract()) - *result_type = left_type; - else if (!right_type->is_abstract()) - *result_type = right_type; - else if (left_type->complex_type() != NULL) - *result_type = left_type; - else if (right_type->complex_type() != NULL) - *result_type = right_type; - else if (left_type->float_type() != NULL) - *result_type = left_type; - else if (right_type->float_type() != NULL) - *result_type = right_type; - else if (left_type->integer_type() != NULL - && left_type->integer_type()->is_rune()) - *result_type = left_type; - else if (right_type->integer_type() != NULL - && right_type->integer_type()->is_rune()) - *result_type = right_type; - else - *result_type = left_type; - - return true; -} - -// Convert an integer comparison code and an operator to a boolean -// value. - -bool -Binary_expression::cmp_to_bool(Operator op, int cmp) -{ - switch (op) - { - case OPERATOR_EQEQ: - return cmp == 0; - break; - case OPERATOR_NOTEQ: - return cmp != 0; - break; - case OPERATOR_LT: - return cmp < 0; - break; - case OPERATOR_LE: - return cmp <= 0; - case OPERATOR_GT: - return cmp > 0; - case OPERATOR_GE: - return cmp >= 0; - default: - go_unreachable(); - } -} - -// Compare constants according to OP. - -bool -Binary_expression::compare_constant(Operator op, Numeric_constant* left_nc, - Numeric_constant* right_nc, - Location location, bool* result) -{ - Type* left_type = left_nc->type(); - Type* right_type = right_nc->type(); - - Type* type; - if (!Binary_expression::operation_type(op, left_type, right_type, &type)) - return false; - - // When comparing an untyped operand to a typed operand, we are - // effectively coercing the untyped operand to the other operand's - // type, so make sure that is valid. - if (!left_nc->set_type(type, true, location) - || !right_nc->set_type(type, true, location)) - return false; - - bool ret; - int cmp; - if (type->complex_type() != NULL) - { - if (op != OPERATOR_EQEQ && op != OPERATOR_NOTEQ) - return false; - ret = Binary_expression::compare_complex(left_nc, right_nc, &cmp); - } - else if (type->float_type() != NULL) - ret = Binary_expression::compare_float(left_nc, right_nc, &cmp); - else - ret = Binary_expression::compare_integer(left_nc, right_nc, &cmp); - - if (ret) - *result = Binary_expression::cmp_to_bool(op, cmp); - - return ret; -} - -// Compare integer constants. - -bool -Binary_expression::compare_integer(const Numeric_constant* left_nc, - const Numeric_constant* right_nc, - int* cmp) -{ - mpz_t left_val; - if (!left_nc->to_int(&left_val)) - return false; - mpz_t right_val; - if (!right_nc->to_int(&right_val)) - { - mpz_clear(left_val); - return false; - } - - *cmp = mpz_cmp(left_val, right_val); - - mpz_clear(left_val); - mpz_clear(right_val); - - return true; -} - -// Compare floating point constants. - -bool -Binary_expression::compare_float(const Numeric_constant* left_nc, - const Numeric_constant* right_nc, - int* cmp) -{ - mpfr_t left_val; - if (!left_nc->to_float(&left_val)) - return false; - mpfr_t right_val; - if (!right_nc->to_float(&right_val)) - { - mpfr_clear(left_val); - return false; - } - - // We already coerced both operands to the same type. If that type - // is not an abstract type, we need to round the values accordingly. - Type* type = left_nc->type(); - if (!type->is_abstract() && type->float_type() != NULL) - { - int bits = type->float_type()->bits(); - mpfr_prec_round(left_val, bits, GMP_RNDN); - mpfr_prec_round(right_val, bits, GMP_RNDN); - } - - *cmp = mpfr_cmp(left_val, right_val); - - mpfr_clear(left_val); - mpfr_clear(right_val); - - return true; -} - -// Compare complex constants. Complex numbers may only be compared -// for equality. - -bool -Binary_expression::compare_complex(const Numeric_constant* left_nc, - const Numeric_constant* right_nc, - int* cmp) -{ - mpfr_t left_real, left_imag; - if (!left_nc->to_complex(&left_real, &left_imag)) - return false; - mpfr_t right_real, right_imag; - if (!right_nc->to_complex(&right_real, &right_imag)) - { - mpfr_clear(left_real); - mpfr_clear(left_imag); - return false; - } - - // We already coerced both operands to the same type. If that type - // is not an abstract type, we need to round the values accordingly. - Type* type = left_nc->type(); - if (!type->is_abstract() && type->complex_type() != NULL) - { - int bits = type->complex_type()->bits(); - mpfr_prec_round(left_real, bits / 2, GMP_RNDN); - mpfr_prec_round(left_imag, bits / 2, GMP_RNDN); - mpfr_prec_round(right_real, bits / 2, GMP_RNDN); - mpfr_prec_round(right_imag, bits / 2, GMP_RNDN); - } - - *cmp = (mpfr_cmp(left_real, right_real) != 0 - || mpfr_cmp(left_imag, right_imag) != 0); - - mpfr_clear(left_real); - mpfr_clear(left_imag); - mpfr_clear(right_real); - mpfr_clear(right_imag); - - return true; -} - -// Apply binary opcode OP to LEFT_NC and RIGHT_NC, setting NC. Return -// true if this could be done, false if not. Issue errors at LOCATION -// as appropriate. - -bool -Binary_expression::eval_constant(Operator op, Numeric_constant* left_nc, - Numeric_constant* right_nc, - Location location, Numeric_constant* nc) -{ - switch (op) - { - case OPERATOR_OROR: - case OPERATOR_ANDAND: - case OPERATOR_EQEQ: - case OPERATOR_NOTEQ: - case OPERATOR_LT: - case OPERATOR_LE: - case OPERATOR_GT: - case OPERATOR_GE: - // These return boolean values, not numeric. - return false; - default: - break; - } - - Type* left_type = left_nc->type(); - Type* right_type = right_nc->type(); - - Type* type; - if (!Binary_expression::operation_type(op, left_type, right_type, &type)) - return false; - - bool is_shift = op == OPERATOR_LSHIFT || op == OPERATOR_RSHIFT; - - // When combining an untyped operand with a typed operand, we are - // effectively coercing the untyped operand to the other operand's - // type, so make sure that is valid. - if (!left_nc->set_type(type, true, location)) - return false; - if (!is_shift && !right_nc->set_type(type, true, location)) - return false; - - bool r; - if (type->complex_type() != NULL) - r = Binary_expression::eval_complex(op, left_nc, right_nc, location, nc); - else if (type->float_type() != NULL) - r = Binary_expression::eval_float(op, left_nc, right_nc, location, nc); - else - r = Binary_expression::eval_integer(op, left_nc, right_nc, location, nc); - - if (r) - r = nc->set_type(type, true, location); - - return r; -} - -// Apply binary opcode OP to LEFT_NC and RIGHT_NC, setting NC, using -// integer operations. Return true if this could be done, false if -// not. - -bool -Binary_expression::eval_integer(Operator op, const Numeric_constant* left_nc, - const Numeric_constant* right_nc, - Location location, Numeric_constant* nc) -{ - mpz_t left_val; - if (!left_nc->to_int(&left_val)) - return false; - mpz_t right_val; - if (!right_nc->to_int(&right_val)) - { - mpz_clear(left_val); - return false; - } - - mpz_t val; - mpz_init(val); - - switch (op) - { - case OPERATOR_PLUS: - mpz_add(val, left_val, right_val); - break; - case OPERATOR_MINUS: - mpz_sub(val, left_val, right_val); - break; - case OPERATOR_OR: - mpz_ior(val, left_val, right_val); - break; - case OPERATOR_XOR: - mpz_xor(val, left_val, right_val); - break; - case OPERATOR_MULT: - mpz_mul(val, left_val, right_val); - break; - case OPERATOR_DIV: - if (mpz_sgn(right_val) != 0) - mpz_tdiv_q(val, left_val, right_val); - else - { - error_at(location, "division by zero"); - mpz_set_ui(val, 0); - } - break; - case OPERATOR_MOD: - if (mpz_sgn(right_val) != 0) - mpz_tdiv_r(val, left_val, right_val); - else - { - error_at(location, "division by zero"); - mpz_set_ui(val, 0); - } - break; - case OPERATOR_LSHIFT: - { - unsigned long shift = mpz_get_ui(right_val); - if (mpz_cmp_ui(right_val, shift) == 0 && shift <= 0x100000) - mpz_mul_2exp(val, left_val, shift); - else - { - error_at(location, "shift count overflow"); - mpz_set_ui(val, 0); - } - break; - } - break; - case OPERATOR_RSHIFT: - { - unsigned long shift = mpz_get_ui(right_val); - if (mpz_cmp_ui(right_val, shift) != 0) - { - error_at(location, "shift count overflow"); - mpz_set_ui(val, 0); - } - else - { - if (mpz_cmp_ui(left_val, 0) >= 0) - mpz_tdiv_q_2exp(val, left_val, shift); - else - mpz_fdiv_q_2exp(val, left_val, shift); - } - break; - } - break; - case OPERATOR_AND: - mpz_and(val, left_val, right_val); - break; - case OPERATOR_BITCLEAR: - { - mpz_t tval; - mpz_init(tval); - mpz_com(tval, right_val); - mpz_and(val, left_val, tval); - mpz_clear(tval); - } - break; - default: - go_unreachable(); - } - - mpz_clear(left_val); - mpz_clear(right_val); - - if (left_nc->is_rune() - || (op != OPERATOR_LSHIFT - && op != OPERATOR_RSHIFT - && right_nc->is_rune())) - nc->set_rune(NULL, val); - else - nc->set_int(NULL, val); - - mpz_clear(val); - - return true; -} - -// Apply binary opcode OP to LEFT_NC and RIGHT_NC, setting NC, using -// floating point operations. Return true if this could be done, -// false if not. - -bool -Binary_expression::eval_float(Operator op, const Numeric_constant* left_nc, - const Numeric_constant* right_nc, - Location location, Numeric_constant* nc) -{ - mpfr_t left_val; - if (!left_nc->to_float(&left_val)) - return false; - mpfr_t right_val; - if (!right_nc->to_float(&right_val)) - { - mpfr_clear(left_val); - return false; - } - - mpfr_t val; - mpfr_init(val); - - bool ret = true; - switch (op) - { - case OPERATOR_PLUS: - mpfr_add(val, left_val, right_val, GMP_RNDN); - break; - case OPERATOR_MINUS: - mpfr_sub(val, left_val, right_val, GMP_RNDN); - break; - case OPERATOR_OR: - case OPERATOR_XOR: - case OPERATOR_AND: - case OPERATOR_BITCLEAR: - case OPERATOR_MOD: - case OPERATOR_LSHIFT: - case OPERATOR_RSHIFT: - mpfr_set_ui(val, 0, GMP_RNDN); - ret = false; - break; - case OPERATOR_MULT: - mpfr_mul(val, left_val, right_val, GMP_RNDN); - break; - case OPERATOR_DIV: - if (!mpfr_zero_p(right_val)) - mpfr_div(val, left_val, right_val, GMP_RNDN); - else - { - error_at(location, "division by zero"); - mpfr_set_ui(val, 0, GMP_RNDN); - } - break; - default: - go_unreachable(); - } - - mpfr_clear(left_val); - mpfr_clear(right_val); - - nc->set_float(NULL, val); - mpfr_clear(val); - - return ret; -} - -// Apply binary opcode OP to LEFT_NC and RIGHT_NC, setting NC, using -// complex operations. Return true if this could be done, false if -// not. - -bool -Binary_expression::eval_complex(Operator op, const Numeric_constant* left_nc, - const Numeric_constant* right_nc, - Location location, Numeric_constant* nc) -{ - mpfr_t left_real, left_imag; - if (!left_nc->to_complex(&left_real, &left_imag)) - return false; - mpfr_t right_real, right_imag; - if (!right_nc->to_complex(&right_real, &right_imag)) - { - mpfr_clear(left_real); - mpfr_clear(left_imag); - return false; - } - - mpfr_t real, imag; - mpfr_init(real); - mpfr_init(imag); - - bool ret = true; - switch (op) - { - case OPERATOR_PLUS: - mpfr_add(real, left_real, right_real, GMP_RNDN); - mpfr_add(imag, left_imag, right_imag, GMP_RNDN); - break; - case OPERATOR_MINUS: - mpfr_sub(real, left_real, right_real, GMP_RNDN); - mpfr_sub(imag, left_imag, right_imag, GMP_RNDN); - break; - case OPERATOR_OR: - case OPERATOR_XOR: - case OPERATOR_AND: - case OPERATOR_BITCLEAR: - case OPERATOR_MOD: - case OPERATOR_LSHIFT: - case OPERATOR_RSHIFT: - mpfr_set_ui(real, 0, GMP_RNDN); - mpfr_set_ui(imag, 0, GMP_RNDN); - ret = false; - break; - case OPERATOR_MULT: - { - // You might think that multiplying two complex numbers would - // be simple, and you would be right, until you start to think - // about getting the right answer for infinity. If one - // operand here is infinity and the other is anything other - // than zero or NaN, then we are going to wind up subtracting - // two infinity values. That will give us a NaN, but the - // correct answer is infinity. - - mpfr_t lrrr; - mpfr_init(lrrr); - mpfr_mul(lrrr, left_real, right_real, GMP_RNDN); - - mpfr_t lrri; - mpfr_init(lrri); - mpfr_mul(lrri, left_real, right_imag, GMP_RNDN); - - mpfr_t lirr; - mpfr_init(lirr); - mpfr_mul(lirr, left_imag, right_real, GMP_RNDN); - - mpfr_t liri; - mpfr_init(liri); - mpfr_mul(liri, left_imag, right_imag, GMP_RNDN); - - mpfr_sub(real, lrrr, liri, GMP_RNDN); - mpfr_add(imag, lrri, lirr, GMP_RNDN); - - // If we get NaN on both sides, check whether it should really - // be infinity. The rule is that if either side of the - // complex number is infinity, then the whole value is - // infinity, even if the other side is NaN. So the only case - // we have to fix is the one in which both sides are NaN. - if (mpfr_nan_p(real) && mpfr_nan_p(imag) - && (!mpfr_nan_p(left_real) || !mpfr_nan_p(left_imag)) - && (!mpfr_nan_p(right_real) || !mpfr_nan_p(right_imag))) - { - bool is_infinity = false; - - mpfr_t lr; - mpfr_t li; - mpfr_init_set(lr, left_real, GMP_RNDN); - mpfr_init_set(li, left_imag, GMP_RNDN); - - mpfr_t rr; - mpfr_t ri; - mpfr_init_set(rr, right_real, GMP_RNDN); - mpfr_init_set(ri, right_imag, GMP_RNDN); - - // If the left side is infinity, then the result is - // infinity. - if (mpfr_inf_p(lr) || mpfr_inf_p(li)) - { - mpfr_set_ui(lr, mpfr_inf_p(lr) ? 1 : 0, GMP_RNDN); - mpfr_copysign(lr, lr, left_real, GMP_RNDN); - mpfr_set_ui(li, mpfr_inf_p(li) ? 1 : 0, GMP_RNDN); - mpfr_copysign(li, li, left_imag, GMP_RNDN); - if (mpfr_nan_p(rr)) - { - mpfr_set_ui(rr, 0, GMP_RNDN); - mpfr_copysign(rr, rr, right_real, GMP_RNDN); - } - if (mpfr_nan_p(ri)) - { - mpfr_set_ui(ri, 0, GMP_RNDN); - mpfr_copysign(ri, ri, right_imag, GMP_RNDN); - } - is_infinity = true; - } - - // If the right side is infinity, then the result is - // infinity. - if (mpfr_inf_p(rr) || mpfr_inf_p(ri)) - { - mpfr_set_ui(rr, mpfr_inf_p(rr) ? 1 : 0, GMP_RNDN); - mpfr_copysign(rr, rr, right_real, GMP_RNDN); - mpfr_set_ui(ri, mpfr_inf_p(ri) ? 1 : 0, GMP_RNDN); - mpfr_copysign(ri, ri, right_imag, GMP_RNDN); - if (mpfr_nan_p(lr)) - { - mpfr_set_ui(lr, 0, GMP_RNDN); - mpfr_copysign(lr, lr, left_real, GMP_RNDN); - } - if (mpfr_nan_p(li)) - { - mpfr_set_ui(li, 0, GMP_RNDN); - mpfr_copysign(li, li, left_imag, GMP_RNDN); - } - is_infinity = true; - } - - // If we got an overflow in the intermediate computations, - // then the result is infinity. - if (!is_infinity - && (mpfr_inf_p(lrrr) || mpfr_inf_p(lrri) - || mpfr_inf_p(lirr) || mpfr_inf_p(liri))) - { - if (mpfr_nan_p(lr)) - { - mpfr_set_ui(lr, 0, GMP_RNDN); - mpfr_copysign(lr, lr, left_real, GMP_RNDN); - } - if (mpfr_nan_p(li)) - { - mpfr_set_ui(li, 0, GMP_RNDN); - mpfr_copysign(li, li, left_imag, GMP_RNDN); - } - if (mpfr_nan_p(rr)) - { - mpfr_set_ui(rr, 0, GMP_RNDN); - mpfr_copysign(rr, rr, right_real, GMP_RNDN); - } - if (mpfr_nan_p(ri)) - { - mpfr_set_ui(ri, 0, GMP_RNDN); - mpfr_copysign(ri, ri, right_imag, GMP_RNDN); - } - is_infinity = true; - } - - if (is_infinity) - { - mpfr_mul(lrrr, lr, rr, GMP_RNDN); - mpfr_mul(lrri, lr, ri, GMP_RNDN); - mpfr_mul(lirr, li, rr, GMP_RNDN); - mpfr_mul(liri, li, ri, GMP_RNDN); - mpfr_sub(real, lrrr, liri, GMP_RNDN); - mpfr_add(imag, lrri, lirr, GMP_RNDN); - mpfr_set_inf(real, mpfr_sgn(real)); - mpfr_set_inf(imag, mpfr_sgn(imag)); - } - - mpfr_clear(lr); - mpfr_clear(li); - mpfr_clear(rr); - mpfr_clear(ri); - } - - mpfr_clear(lrrr); - mpfr_clear(lrri); - mpfr_clear(lirr); - mpfr_clear(liri); - } - break; - case OPERATOR_DIV: - { - // For complex division we want to avoid having an - // intermediate overflow turn the whole result in a NaN. We - // scale the values to try to avoid this. - - if (mpfr_zero_p(right_real) && mpfr_zero_p(right_imag)) - { - error_at(location, "division by zero"); - mpfr_set_ui(real, 0, GMP_RNDN); - mpfr_set_ui(imag, 0, GMP_RNDN); - break; - } - - mpfr_t rra; - mpfr_t ria; - mpfr_init(rra); - mpfr_init(ria); - mpfr_abs(rra, right_real, GMP_RNDN); - mpfr_abs(ria, right_imag, GMP_RNDN); - mpfr_t t; - mpfr_init(t); - mpfr_max(t, rra, ria, GMP_RNDN); - - mpfr_t rr; - mpfr_t ri; - mpfr_init_set(rr, right_real, GMP_RNDN); - mpfr_init_set(ri, right_imag, GMP_RNDN); - long ilogbw = 0; - if (!mpfr_inf_p(t) && !mpfr_nan_p(t) && !mpfr_zero_p(t)) - { - ilogbw = mpfr_get_exp(t); - mpfr_mul_2si(rr, rr, - ilogbw, GMP_RNDN); - mpfr_mul_2si(ri, ri, - ilogbw, GMP_RNDN); - } - - mpfr_t denom; - mpfr_init(denom); - mpfr_mul(denom, rr, rr, GMP_RNDN); - mpfr_mul(t, ri, ri, GMP_RNDN); - mpfr_add(denom, denom, t, GMP_RNDN); - - mpfr_mul(real, left_real, rr, GMP_RNDN); - mpfr_mul(t, left_imag, ri, GMP_RNDN); - mpfr_add(real, real, t, GMP_RNDN); - mpfr_div(real, real, denom, GMP_RNDN); - mpfr_mul_2si(real, real, - ilogbw, GMP_RNDN); - - mpfr_mul(imag, left_imag, rr, GMP_RNDN); - mpfr_mul(t, left_real, ri, GMP_RNDN); - mpfr_sub(imag, imag, t, GMP_RNDN); - mpfr_div(imag, imag, denom, GMP_RNDN); - mpfr_mul_2si(imag, imag, - ilogbw, GMP_RNDN); - - // If we wind up with NaN on both sides, check whether we - // should really have infinity. The rule is that if either - // side of the complex number is infinity, then the whole - // value is infinity, even if the other side is NaN. So the - // only case we have to fix is the one in which both sides are - // NaN. - if (mpfr_nan_p(real) && mpfr_nan_p(imag) - && (!mpfr_nan_p(left_real) || !mpfr_nan_p(left_imag)) - && (!mpfr_nan_p(right_real) || !mpfr_nan_p(right_imag))) - { - if (mpfr_zero_p(denom)) - { - mpfr_set_inf(real, mpfr_sgn(rr)); - mpfr_mul(real, real, left_real, GMP_RNDN); - mpfr_set_inf(imag, mpfr_sgn(rr)); - mpfr_mul(imag, imag, left_imag, GMP_RNDN); - } - else if ((mpfr_inf_p(left_real) || mpfr_inf_p(left_imag)) - && mpfr_number_p(rr) && mpfr_number_p(ri)) - { - mpfr_set_ui(t, mpfr_inf_p(left_real) ? 1 : 0, GMP_RNDN); - mpfr_copysign(t, t, left_real, GMP_RNDN); - - mpfr_t t2; - mpfr_init_set_ui(t2, mpfr_inf_p(left_imag) ? 1 : 0, GMP_RNDN); - mpfr_copysign(t2, t2, left_imag, GMP_RNDN); - - mpfr_t t3; - mpfr_init(t3); - mpfr_mul(t3, t, rr, GMP_RNDN); - - mpfr_t t4; - mpfr_init(t4); - mpfr_mul(t4, t2, ri, GMP_RNDN); - - mpfr_add(t3, t3, t4, GMP_RNDN); - mpfr_set_inf(real, mpfr_sgn(t3)); - - mpfr_mul(t3, t2, rr, GMP_RNDN); - mpfr_mul(t4, t, ri, GMP_RNDN); - mpfr_sub(t3, t3, t4, GMP_RNDN); - mpfr_set_inf(imag, mpfr_sgn(t3)); - - mpfr_clear(t2); - mpfr_clear(t3); - mpfr_clear(t4); - } - else if ((mpfr_inf_p(right_real) || mpfr_inf_p(right_imag)) - && mpfr_number_p(left_real) && mpfr_number_p(left_imag)) - { - mpfr_set_ui(t, mpfr_inf_p(rr) ? 1 : 0, GMP_RNDN); - mpfr_copysign(t, t, rr, GMP_RNDN); - - mpfr_t t2; - mpfr_init_set_ui(t2, mpfr_inf_p(ri) ? 1 : 0, GMP_RNDN); - mpfr_copysign(t2, t2, ri, GMP_RNDN); - - mpfr_t t3; - mpfr_init(t3); - mpfr_mul(t3, left_real, t, GMP_RNDN); - - mpfr_t t4; - mpfr_init(t4); - mpfr_mul(t4, left_imag, t2, GMP_RNDN); - - mpfr_add(t3, t3, t4, GMP_RNDN); - mpfr_set_ui(real, 0, GMP_RNDN); - mpfr_mul(real, real, t3, GMP_RNDN); - - mpfr_mul(t3, left_imag, t, GMP_RNDN); - mpfr_mul(t4, left_real, t2, GMP_RNDN); - mpfr_sub(t3, t3, t4, GMP_RNDN); - mpfr_set_ui(imag, 0, GMP_RNDN); - mpfr_mul(imag, imag, t3, GMP_RNDN); - - mpfr_clear(t2); - mpfr_clear(t3); - mpfr_clear(t4); - } - } - - mpfr_clear(denom); - mpfr_clear(rr); - mpfr_clear(ri); - mpfr_clear(t); - mpfr_clear(rra); - mpfr_clear(ria); - } - break; - default: - go_unreachable(); - } - - mpfr_clear(left_real); - mpfr_clear(left_imag); - mpfr_clear(right_real); - mpfr_clear(right_imag); - - nc->set_complex(NULL, real, imag); - mpfr_clear(real); - mpfr_clear(imag); - - return ret; -} - -// Lower a binary expression. We have to evaluate constant -// expressions now, in order to implement Go's unlimited precision -// constants. - -Expression* -Binary_expression::do_lower(Gogo* gogo, Named_object*, - Statement_inserter* inserter, int) -{ - Location location = this->location(); - Operator op = this->op_; - Expression* left = this->left_; - Expression* right = this->right_; - - const bool is_comparison = (op == OPERATOR_EQEQ - || op == OPERATOR_NOTEQ - || op == OPERATOR_LT - || op == OPERATOR_LE - || op == OPERATOR_GT - || op == OPERATOR_GE); - - // Numeric constant expressions. - { - Numeric_constant left_nc; - Numeric_constant right_nc; - if (left->numeric_constant_value(&left_nc) - && right->numeric_constant_value(&right_nc)) - { - if (is_comparison) - { - bool result; - if (!Binary_expression::compare_constant(op, &left_nc, - &right_nc, location, - &result)) - return this; - return Expression::make_cast(Type::make_boolean_type(), - Expression::make_boolean(result, - location), - location); - } - else - { - Numeric_constant nc; - if (!Binary_expression::eval_constant(op, &left_nc, &right_nc, - location, &nc)) - return this; - return nc.expression(location); - } - } - } - - // String constant expressions. - if (left->type()->is_string_type() && right->type()->is_string_type()) - { - std::string left_string; - std::string right_string; - if (left->string_constant_value(&left_string) - && right->string_constant_value(&right_string)) - { - if (op == OPERATOR_PLUS) - return Expression::make_string(left_string + right_string, - location); - else if (is_comparison) - { - int cmp = left_string.compare(right_string); - bool r = Binary_expression::cmp_to_bool(op, cmp); - return Expression::make_boolean(r, location); - } - } - } - - // Lower struct and array comparisons. - if (op == OPERATOR_EQEQ || op == OPERATOR_NOTEQ) - { - if (left->type()->struct_type() != NULL) - return this->lower_struct_comparison(gogo, inserter); - else if (left->type()->array_type() != NULL - && !left->type()->is_slice_type()) - return this->lower_array_comparison(gogo, inserter); - } - - return this; -} - -// Lower a struct comparison. - -Expression* -Binary_expression::lower_struct_comparison(Gogo* gogo, - Statement_inserter* inserter) -{ - Struct_type* st = this->left_->type()->struct_type(); - Struct_type* st2 = this->right_->type()->struct_type(); - if (st2 == NULL) - return this; - if (st != st2 && !Type::are_identical(st, st2, false, NULL)) - return this; - if (!Type::are_compatible_for_comparison(true, this->left_->type(), - this->right_->type(), NULL)) - return this; - - // See if we can compare using memcmp. As a heuristic, we use - // memcmp rather than field references and comparisons if there are - // more than two fields. - if (st->compare_is_identity(gogo) && st->total_field_count() > 2) - return this->lower_compare_to_memcmp(gogo, inserter); - - Location loc = this->location(); - - Expression* left = this->left_; - Temporary_statement* left_temp = NULL; - if (left->var_expression() == NULL - && left->temporary_reference_expression() == NULL) - { - left_temp = Statement::make_temporary(left->type(), NULL, loc); - inserter->insert(left_temp); - left = Expression::make_set_and_use_temporary(left_temp, left, loc); - } - - Expression* right = this->right_; - Temporary_statement* right_temp = NULL; - if (right->var_expression() == NULL - && right->temporary_reference_expression() == NULL) - { - right_temp = Statement::make_temporary(right->type(), NULL, loc); - inserter->insert(right_temp); - right = Expression::make_set_and_use_temporary(right_temp, right, loc); - } - - Expression* ret = Expression::make_boolean(true, loc); - const Struct_field_list* fields = st->fields(); - unsigned int field_index = 0; - for (Struct_field_list::const_iterator pf = fields->begin(); - pf != fields->end(); - ++pf, ++field_index) - { - if (Gogo::is_sink_name(pf->field_name())) - continue; - - if (field_index > 0) - { - if (left_temp == NULL) - left = left->copy(); - else - left = Expression::make_temporary_reference(left_temp, loc); - if (right_temp == NULL) - right = right->copy(); - else - right = Expression::make_temporary_reference(right_temp, loc); - } - Expression* f1 = Expression::make_field_reference(left, field_index, - loc); - Expression* f2 = Expression::make_field_reference(right, field_index, - loc); - Expression* cond = Expression::make_binary(OPERATOR_EQEQ, f1, f2, loc); - ret = Expression::make_binary(OPERATOR_ANDAND, ret, cond, loc); - } - - if (this->op_ == OPERATOR_NOTEQ) - ret = Expression::make_unary(OPERATOR_NOT, ret, loc); - - return ret; -} - -// Lower an array comparison. - -Expression* -Binary_expression::lower_array_comparison(Gogo* gogo, - Statement_inserter* inserter) -{ - Array_type* at = this->left_->type()->array_type(); - Array_type* at2 = this->right_->type()->array_type(); - if (at2 == NULL) - return this; - if (at != at2 && !Type::are_identical(at, at2, false, NULL)) - return this; - if (!Type::are_compatible_for_comparison(true, this->left_->type(), - this->right_->type(), NULL)) - return this; - - // Call memcmp directly if possible. This may let the middle-end - // optimize the call. - if (at->compare_is_identity(gogo)) - return this->lower_compare_to_memcmp(gogo, inserter); - - // Call the array comparison function. - Named_object* hash_fn; - Named_object* equal_fn; - at->type_functions(gogo, this->left_->type()->named_type(), NULL, NULL, - &hash_fn, &equal_fn); - - Location loc = this->location(); - - Expression* func = Expression::make_func_reference(equal_fn, NULL, loc); - - Expression_list* args = new Expression_list(); - args->push_back(this->operand_address(inserter, this->left_)); - args->push_back(this->operand_address(inserter, this->right_)); - args->push_back(Expression::make_type_info(at, TYPE_INFO_SIZE)); - - Expression* ret = Expression::make_call(func, args, false, loc); - - if (this->op_ == OPERATOR_NOTEQ) - ret = Expression::make_unary(OPERATOR_NOT, ret, loc); - - return ret; -} - -// Lower a struct or array comparison to a call to memcmp. - -Expression* -Binary_expression::lower_compare_to_memcmp(Gogo*, Statement_inserter* inserter) -{ - Location loc = this->location(); - - Expression* a1 = this->operand_address(inserter, this->left_); - Expression* a2 = this->operand_address(inserter, this->right_); - Expression* len = Expression::make_type_info(this->left_->type(), - TYPE_INFO_SIZE); - - Expression* call = Runtime::make_call(Runtime::MEMCMP, loc, 3, a1, a2, len); - - mpz_t zval; - mpz_init_set_ui(zval, 0); - Expression* zero = Expression::make_integer(&zval, NULL, loc); - mpz_clear(zval); - - return Expression::make_binary(this->op_, call, zero, loc); -} - -// Return the address of EXPR, cast to unsafe.Pointer. - -Expression* -Binary_expression::operand_address(Statement_inserter* inserter, - Expression* expr) -{ - Location loc = this->location(); - - if (!expr->is_addressable()) - { - Temporary_statement* temp = Statement::make_temporary(expr->type(), NULL, - loc); - inserter->insert(temp); - expr = Expression::make_set_and_use_temporary(temp, expr, loc); - } - expr = Expression::make_unary(OPERATOR_AND, expr, loc); - static_cast<Unary_expression*>(expr)->set_does_not_escape(); - Type* void_type = Type::make_void_type(); - Type* unsafe_pointer_type = Type::make_pointer_type(void_type); - return Expression::make_cast(unsafe_pointer_type, expr, loc); -} - -// Return the numeric constant value, if it has one. - -bool -Binary_expression::do_numeric_constant_value(Numeric_constant* nc) const -{ - Numeric_constant left_nc; - if (!this->left_->numeric_constant_value(&left_nc)) - return false; - Numeric_constant right_nc; - if (!this->right_->numeric_constant_value(&right_nc)) - return false; - return Binary_expression::eval_constant(this->op_, &left_nc, &right_nc, - this->location(), nc); -} - -// Note that the value is being discarded. - -bool -Binary_expression::do_discarding_value() -{ - if (this->op_ == OPERATOR_OROR || this->op_ == OPERATOR_ANDAND) - return this->right_->discarding_value(); - else - { - this->unused_value_error(); - return false; - } -} - -// Get type. - -Type* -Binary_expression::do_type() -{ - if (this->classification() == EXPRESSION_ERROR) - return Type::make_error_type(); - - switch (this->op_) - { - case OPERATOR_EQEQ: - case OPERATOR_NOTEQ: - case OPERATOR_LT: - case OPERATOR_LE: - case OPERATOR_GT: - case OPERATOR_GE: - if (this->type_ == NULL) - this->type_ = Type::make_boolean_type(); - return this->type_; - - case OPERATOR_PLUS: - case OPERATOR_MINUS: - case OPERATOR_OR: - case OPERATOR_XOR: - case OPERATOR_MULT: - case OPERATOR_DIV: - case OPERATOR_MOD: - case OPERATOR_AND: - case OPERATOR_BITCLEAR: - case OPERATOR_OROR: - case OPERATOR_ANDAND: - { - Type* type; - if (!Binary_expression::operation_type(this->op_, - this->left_->type(), - this->right_->type(), - &type)) - return Type::make_error_type(); - return type; - } - - case OPERATOR_LSHIFT: - case OPERATOR_RSHIFT: - return this->left_->type(); - - default: - go_unreachable(); - } -} - -// Set type for a binary expression. - -void -Binary_expression::do_determine_type(const Type_context* context) -{ - Type* tleft = this->left_->type(); - Type* tright = this->right_->type(); - - // Both sides should have the same type, except for the shift - // operations. For a comparison, we should ignore the incoming - // type. - - bool is_shift_op = (this->op_ == OPERATOR_LSHIFT - || this->op_ == OPERATOR_RSHIFT); - - bool is_comparison = (this->op_ == OPERATOR_EQEQ - || this->op_ == OPERATOR_NOTEQ - || this->op_ == OPERATOR_LT - || this->op_ == OPERATOR_LE - || this->op_ == OPERATOR_GT - || this->op_ == OPERATOR_GE); - - Type_context subcontext(*context); - - if (is_comparison) - { - // In a comparison, the context does not determine the types of - // the operands. - subcontext.type = NULL; - } - - // Set the context for the left hand operand. - if (is_shift_op) - { - // The right hand operand of a shift plays no role in - // determining the type of the left hand operand. - } - else if (!tleft->is_abstract()) - subcontext.type = tleft; - else if (!tright->is_abstract()) - subcontext.type = tright; - else if (subcontext.type == NULL) - { - if ((tleft->integer_type() != NULL && tright->integer_type() != NULL) - || (tleft->float_type() != NULL && tright->float_type() != NULL) - || (tleft->complex_type() != NULL && tright->complex_type() != NULL)) - { - // Both sides have an abstract integer, abstract float, or - // abstract complex type. Just let CONTEXT determine - // whether they may remain abstract or not. - } - else if (tleft->complex_type() != NULL) - subcontext.type = tleft; - else if (tright->complex_type() != NULL) - subcontext.type = tright; - else if (tleft->float_type() != NULL) - subcontext.type = tleft; - else if (tright->float_type() != NULL) - subcontext.type = tright; - else - subcontext.type = tleft; - - if (subcontext.type != NULL && !context->may_be_abstract) - subcontext.type = subcontext.type->make_non_abstract_type(); - } - - this->left_->determine_type(&subcontext); - - if (is_shift_op) - { - // We may have inherited an unusable type for the shift operand. - // Give a useful error if that happened. - if (tleft->is_abstract() - && subcontext.type != NULL - && !subcontext.may_be_abstract - && subcontext.type->integer_type() == NULL) - this->report_error(("invalid context-determined non-integer type " - "for left operand of shift")); - - // The context for the right hand operand is the same as for the - // left hand operand, except for a shift operator. - subcontext.type = Type::lookup_integer_type("uint"); - subcontext.may_be_abstract = false; - } - - this->right_->determine_type(&subcontext); - - if (is_comparison) - { - if (this->type_ != NULL && !this->type_->is_abstract()) - ; - else if (context->type != NULL && context->type->is_boolean_type()) - this->type_ = context->type; - else if (!context->may_be_abstract) - this->type_ = Type::lookup_bool_type(); - } -} - -// Report an error if the binary operator OP does not support TYPE. -// OTYPE is the type of the other operand. Return whether the -// operation is OK. This should not be used for shift. - -bool -Binary_expression::check_operator_type(Operator op, Type* type, Type* otype, - Location location) -{ - switch (op) - { - case OPERATOR_OROR: - case OPERATOR_ANDAND: - if (!type->is_boolean_type()) - { - error_at(location, "expected boolean type"); - return false; - } - break; - - case OPERATOR_EQEQ: - case OPERATOR_NOTEQ: - { - std::string reason; - if (!Type::are_compatible_for_comparison(true, type, otype, &reason)) - { - error_at(location, "%s", reason.c_str()); - return false; - } - } - break; - - case OPERATOR_LT: - case OPERATOR_LE: - case OPERATOR_GT: - case OPERATOR_GE: - { - std::string reason; - if (!Type::are_compatible_for_comparison(false, type, otype, &reason)) - { - error_at(location, "%s", reason.c_str()); - return false; - } - } - break; - - case OPERATOR_PLUS: - case OPERATOR_PLUSEQ: - if (type->integer_type() == NULL - && type->float_type() == NULL - && type->complex_type() == NULL - && !type->is_string_type()) - { - error_at(location, - "expected integer, floating, complex, or string type"); - return false; - } - break; - - case OPERATOR_MINUS: - case OPERATOR_MINUSEQ: - case OPERATOR_MULT: - case OPERATOR_MULTEQ: - case OPERATOR_DIV: - case OPERATOR_DIVEQ: - if (type->integer_type() == NULL - && type->float_type() == NULL - && type->complex_type() == NULL) - { - error_at(location, "expected integer, floating, or complex type"); - return false; - } - break; - - case OPERATOR_MOD: - case OPERATOR_MODEQ: - case OPERATOR_OR: - case OPERATOR_OREQ: - case OPERATOR_AND: - case OPERATOR_ANDEQ: - case OPERATOR_XOR: - case OPERATOR_XOREQ: - case OPERATOR_BITCLEAR: - case OPERATOR_BITCLEAREQ: - if (type->integer_type() == NULL) - { - error_at(location, "expected integer type"); - return false; - } - break; - - default: - go_unreachable(); - } - - return true; -} - -// Check types. - -void -Binary_expression::do_check_types(Gogo*) -{ - if (this->classification() == EXPRESSION_ERROR) - return; - - Type* left_type = this->left_->type(); - Type* right_type = this->right_->type(); - if (left_type->is_error() || right_type->is_error()) - { - this->set_is_error(); - return; - } - - if (this->op_ == OPERATOR_EQEQ - || this->op_ == OPERATOR_NOTEQ - || this->op_ == OPERATOR_LT - || this->op_ == OPERATOR_LE - || this->op_ == OPERATOR_GT - || this->op_ == OPERATOR_GE) - { - if (left_type->is_nil_type() && right_type->is_nil_type()) - { - this->report_error(_("invalid comparison of nil with nil")); - return; - } - if (!Type::are_assignable(left_type, right_type, NULL) - && !Type::are_assignable(right_type, left_type, NULL)) - { - this->report_error(_("incompatible types in binary expression")); - return; - } - if (!Binary_expression::check_operator_type(this->op_, left_type, - right_type, - this->location()) - || !Binary_expression::check_operator_type(this->op_, right_type, - left_type, - this->location())) - { - this->set_is_error(); - return; - } - } - else if (this->op_ != OPERATOR_LSHIFT && this->op_ != OPERATOR_RSHIFT) - { - if (!Type::are_compatible_for_binop(left_type, right_type)) - { - this->report_error(_("incompatible types in binary expression")); - return; - } - if (!Binary_expression::check_operator_type(this->op_, left_type, - right_type, - this->location())) - { - this->set_is_error(); - return; - } - } - else - { - if (left_type->integer_type() == NULL) - this->report_error(_("shift of non-integer operand")); - - if (!right_type->is_abstract() - && (right_type->integer_type() == NULL - || !right_type->integer_type()->is_unsigned())) - this->report_error(_("shift count not unsigned integer")); - else - { - Numeric_constant nc; - if (this->right_->numeric_constant_value(&nc)) - { - mpz_t val; - if (!nc.to_int(&val)) - this->report_error(_("shift count not unsigned integer")); - else - { - if (mpz_sgn(val) < 0) - { - this->report_error(_("negative shift count")); - mpz_set_ui(val, 0); - Location rloc = this->right_->location(); - this->right_ = Expression::make_integer(&val, right_type, - rloc); - } - mpz_clear(val); - } - } - } - } -} - -// Get a tree for a binary expression. - -tree -Binary_expression::do_get_tree(Translate_context* context) -{ - Gogo* gogo = context->gogo(); - - tree left = this->left_->get_tree(context); - tree right = this->right_->get_tree(context); - - if (left == error_mark_node || right == error_mark_node) - return error_mark_node; - - enum tree_code code; - bool use_left_type = true; - bool is_shift_op = false; - bool is_idiv_op = false; - switch (this->op_) - { - case OPERATOR_EQEQ: - case OPERATOR_NOTEQ: - case OPERATOR_LT: - case OPERATOR_LE: - case OPERATOR_GT: - case OPERATOR_GE: - return Expression::comparison_tree(context, this->type_, this->op_, - this->left_->type(), left, - this->right_->type(), right, - this->location()); - - case OPERATOR_OROR: - code = TRUTH_ORIF_EXPR; - use_left_type = false; - break; - case OPERATOR_ANDAND: - code = TRUTH_ANDIF_EXPR; - use_left_type = false; - break; - case OPERATOR_PLUS: - code = PLUS_EXPR; - break; - case OPERATOR_MINUS: - code = MINUS_EXPR; - break; - case OPERATOR_OR: - code = BIT_IOR_EXPR; - break; - case OPERATOR_XOR: - code = BIT_XOR_EXPR; - break; - case OPERATOR_MULT: - code = MULT_EXPR; - break; - case OPERATOR_DIV: - { - Type *t = this->left_->type(); - if (t->float_type() != NULL || t->complex_type() != NULL) - code = RDIV_EXPR; - else - { - code = TRUNC_DIV_EXPR; - is_idiv_op = true; - } - } - break; - case OPERATOR_MOD: - code = TRUNC_MOD_EXPR; - is_idiv_op = true; - break; - case OPERATOR_LSHIFT: - code = LSHIFT_EXPR; - is_shift_op = true; - break; - case OPERATOR_RSHIFT: - code = RSHIFT_EXPR; - is_shift_op = true; - break; - case OPERATOR_AND: - code = BIT_AND_EXPR; - break; - case OPERATOR_BITCLEAR: - right = fold_build1(BIT_NOT_EXPR, TREE_TYPE(right), right); - code = BIT_AND_EXPR; - break; - default: - go_unreachable(); - } - - location_t gccloc = this->location().gcc_location(); - tree type = use_left_type ? TREE_TYPE(left) : TREE_TYPE(right); - - if (this->left_->type()->is_string_type()) - { - go_assert(this->op_ == OPERATOR_PLUS); - Type* st = Type::make_string_type(); - tree string_type = type_to_tree(st->get_backend(gogo)); - static tree string_plus_decl; - return Gogo::call_builtin(&string_plus_decl, - this->location(), - "__go_string_plus", - 2, - string_type, - string_type, - left, - string_type, - right); - } - - tree compute_type = excess_precision_type(type); - if (compute_type != NULL_TREE) - { - left = ::convert(compute_type, left); - right = ::convert(compute_type, right); - } - - tree eval_saved = NULL_TREE; - if (is_shift_op - || (is_idiv_op && (go_check_divide_zero || go_check_divide_overflow))) - { - // Make sure the values are evaluated. - if (!DECL_P(left)) - { - left = save_expr(left); - eval_saved = left; - } - if (!DECL_P(right)) - { - right = save_expr(right); - if (eval_saved == NULL_TREE) - eval_saved = right; - else - eval_saved = fold_build2_loc(gccloc, COMPOUND_EXPR, - void_type_node, eval_saved, right); - } - } - - tree ret = fold_build2_loc(gccloc, code, - compute_type != NULL_TREE ? compute_type : type, - left, right); - - if (compute_type != NULL_TREE) - ret = ::convert(type, ret); - - // In Go, a shift larger than the size of the type is well-defined. - // This is not true in GENERIC, so we need to insert a conditional. - if (is_shift_op) - { - go_assert(INTEGRAL_TYPE_P(TREE_TYPE(left))); - go_assert(this->left_->type()->integer_type() != NULL); - int bits = TYPE_PRECISION(TREE_TYPE(left)); - - tree compare = fold_build2(LT_EXPR, boolean_type_node, right, - build_int_cst_type(TREE_TYPE(right), bits)); - - tree overflow_result = fold_convert_loc(gccloc, TREE_TYPE(left), - integer_zero_node); - if (this->op_ == OPERATOR_RSHIFT - && !this->left_->type()->integer_type()->is_unsigned()) - { - tree neg = - fold_build2_loc(gccloc, LT_EXPR, boolean_type_node, - left, - fold_convert_loc(gccloc, TREE_TYPE(left), - integer_zero_node)); - tree neg_one = - fold_build2_loc(gccloc, MINUS_EXPR, TREE_TYPE(left), - fold_convert_loc(gccloc, TREE_TYPE(left), - integer_zero_node), - fold_convert_loc(gccloc, TREE_TYPE(left), - integer_one_node)); - overflow_result = - fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(left), - neg, neg_one, overflow_result); - } - - ret = fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(left), - compare, ret, overflow_result); - - if (eval_saved != NULL_TREE) - ret = fold_build2_loc(gccloc, COMPOUND_EXPR, TREE_TYPE(ret), - eval_saved, ret); - } - - // Add checks for division by zero and division overflow as needed. - if (is_idiv_op) - { - if (go_check_divide_zero) - { - // right == 0 - tree check = fold_build2_loc(gccloc, EQ_EXPR, boolean_type_node, - right, - fold_convert_loc(gccloc, - TREE_TYPE(right), - integer_zero_node)); - - // __go_runtime_error(RUNTIME_ERROR_DIVISION_BY_ZERO), 0 - int errcode = RUNTIME_ERROR_DIVISION_BY_ZERO; - tree panic = fold_build2_loc(gccloc, COMPOUND_EXPR, TREE_TYPE(ret), - gogo->runtime_error(errcode, - this->location()), - fold_convert_loc(gccloc, TREE_TYPE(ret), - integer_zero_node)); - - // right == 0 ? (__go_runtime_error(...), 0) : ret - ret = fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(ret), - check, panic, ret); - } - - if (go_check_divide_overflow) - { - // right == -1 - // FIXME: It would be nice to say that this test is expected - // to return false. - tree m1 = integer_minus_one_node; - tree check = fold_build2_loc(gccloc, EQ_EXPR, boolean_type_node, - right, - fold_convert_loc(gccloc, - TREE_TYPE(right), - m1)); - - tree overflow; - if (TYPE_UNSIGNED(TREE_TYPE(ret))) - { - // An unsigned -1 is the largest possible number, so - // dividing is always 1 or 0. - tree cmp = fold_build2_loc(gccloc, EQ_EXPR, boolean_type_node, - left, right); - if (this->op_ == OPERATOR_DIV) - overflow = fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(ret), - cmp, - fold_convert_loc(gccloc, - TREE_TYPE(ret), - integer_one_node), - fold_convert_loc(gccloc, - TREE_TYPE(ret), - integer_zero_node)); - else - overflow = fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(ret), - cmp, - fold_convert_loc(gccloc, - TREE_TYPE(ret), - integer_zero_node), - left); - } - else - { - // Computing left / -1 is the same as computing - left, - // which does not overflow since Go sets -fwrapv. - if (this->op_ == OPERATOR_DIV) - overflow = fold_build1_loc(gccloc, NEGATE_EXPR, TREE_TYPE(left), - left); - else - overflow = integer_zero_node; - } - overflow = fold_convert_loc(gccloc, TREE_TYPE(ret), overflow); - - // right == -1 ? - left : ret - ret = fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(ret), - check, overflow, ret); - } - - if (eval_saved != NULL_TREE) - ret = fold_build2_loc(gccloc, COMPOUND_EXPR, TREE_TYPE(ret), - eval_saved, ret); - } - - return ret; -} - -// Export a binary expression. - -void -Binary_expression::do_export(Export* exp) const -{ - exp->write_c_string("("); - this->left_->export_expression(exp); - switch (this->op_) - { - case OPERATOR_OROR: - exp->write_c_string(" || "); - break; - case OPERATOR_ANDAND: - exp->write_c_string(" && "); - break; - case OPERATOR_EQEQ: - exp->write_c_string(" == "); - break; - case OPERATOR_NOTEQ: - exp->write_c_string(" != "); - break; - case OPERATOR_LT: - exp->write_c_string(" < "); - break; - case OPERATOR_LE: - exp->write_c_string(" <= "); - break; - case OPERATOR_GT: - exp->write_c_string(" > "); - break; - case OPERATOR_GE: - exp->write_c_string(" >= "); - break; - case OPERATOR_PLUS: - exp->write_c_string(" + "); - break; - case OPERATOR_MINUS: - exp->write_c_string(" - "); - break; - case OPERATOR_OR: - exp->write_c_string(" | "); - break; - case OPERATOR_XOR: - exp->write_c_string(" ^ "); - break; - case OPERATOR_MULT: - exp->write_c_string(" * "); - break; - case OPERATOR_DIV: - exp->write_c_string(" / "); - break; - case OPERATOR_MOD: - exp->write_c_string(" % "); - break; - case OPERATOR_LSHIFT: - exp->write_c_string(" << "); - break; - case OPERATOR_RSHIFT: - exp->write_c_string(" >> "); - break; - case OPERATOR_AND: - exp->write_c_string(" & "); - break; - case OPERATOR_BITCLEAR: - exp->write_c_string(" &^ "); - break; - default: - go_unreachable(); - } - this->right_->export_expression(exp); - exp->write_c_string(")"); -} - -// Import a binary expression. - -Expression* -Binary_expression::do_import(Import* imp) -{ - imp->require_c_string("("); - - Expression* left = Expression::import_expression(imp); - - Operator op; - if (imp->match_c_string(" || ")) - { - op = OPERATOR_OROR; - imp->advance(4); - } - else if (imp->match_c_string(" && ")) - { - op = OPERATOR_ANDAND; - imp->advance(4); - } - else if (imp->match_c_string(" == ")) - { - op = OPERATOR_EQEQ; - imp->advance(4); - } - else if (imp->match_c_string(" != ")) - { - op = OPERATOR_NOTEQ; - imp->advance(4); - } - else if (imp->match_c_string(" < ")) - { - op = OPERATOR_LT; - imp->advance(3); - } - else if (imp->match_c_string(" <= ")) - { - op = OPERATOR_LE; - imp->advance(4); - } - else if (imp->match_c_string(" > ")) - { - op = OPERATOR_GT; - imp->advance(3); - } - else if (imp->match_c_string(" >= ")) - { - op = OPERATOR_GE; - imp->advance(4); - } - else if (imp->match_c_string(" + ")) - { - op = OPERATOR_PLUS; - imp->advance(3); - } - else if (imp->match_c_string(" - ")) - { - op = OPERATOR_MINUS; - imp->advance(3); - } - else if (imp->match_c_string(" | ")) - { - op = OPERATOR_OR; - imp->advance(3); - } - else if (imp->match_c_string(" ^ ")) - { - op = OPERATOR_XOR; - imp->advance(3); - } - else if (imp->match_c_string(" * ")) - { - op = OPERATOR_MULT; - imp->advance(3); - } - else if (imp->match_c_string(" / ")) - { - op = OPERATOR_DIV; - imp->advance(3); - } - else if (imp->match_c_string(" % ")) - { - op = OPERATOR_MOD; - imp->advance(3); - } - else if (imp->match_c_string(" << ")) - { - op = OPERATOR_LSHIFT; - imp->advance(4); - } - else if (imp->match_c_string(" >> ")) - { - op = OPERATOR_RSHIFT; - imp->advance(4); - } - else if (imp->match_c_string(" & ")) - { - op = OPERATOR_AND; - imp->advance(3); - } - else if (imp->match_c_string(" &^ ")) - { - op = OPERATOR_BITCLEAR; - imp->advance(4); - } - else - { - error_at(imp->location(), "unrecognized binary operator"); - return Expression::make_error(imp->location()); - } - - Expression* right = Expression::import_expression(imp); - - imp->require_c_string(")"); - - return Expression::make_binary(op, left, right, imp->location()); -} - -// Dump ast representation of a binary expression. - -void -Binary_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const -{ - ast_dump_context->ostream() << "("; - ast_dump_context->dump_expression(this->left_); - ast_dump_context->ostream() << " "; - ast_dump_context->dump_operator(this->op_); - ast_dump_context->ostream() << " "; - ast_dump_context->dump_expression(this->right_); - ast_dump_context->ostream() << ") "; -} - -// Make a binary expression. - -Expression* -Expression::make_binary(Operator op, Expression* left, Expression* right, - Location location) -{ - return new Binary_expression(op, left, right, location); -} - -// Implement a comparison. - -tree -Expression::comparison_tree(Translate_context* context, Type* result_type, - Operator op, Type* left_type, tree left_tree, - Type* right_type, tree right_tree, - Location location) -{ - Type* int_type = Type::lookup_integer_type("int"); - tree int_type_tree = type_to_tree(int_type->get_backend(context->gogo())); - - enum tree_code code; - switch (op) - { - case OPERATOR_EQEQ: - code = EQ_EXPR; - break; - case OPERATOR_NOTEQ: - code = NE_EXPR; - break; - case OPERATOR_LT: - code = LT_EXPR; - break; - case OPERATOR_LE: - code = LE_EXPR; - break; - case OPERATOR_GT: - code = GT_EXPR; - break; - case OPERATOR_GE: - code = GE_EXPR; - break; - default: - go_unreachable(); - } - - if (left_type->is_string_type() && right_type->is_string_type()) - { - Type* st = Type::make_string_type(); - tree string_type = type_to_tree(st->get_backend(context->gogo())); - static tree string_compare_decl; - left_tree = Gogo::call_builtin(&string_compare_decl, - location, - "__go_strcmp", - 2, - int_type_tree, - string_type, - left_tree, - string_type, - right_tree); - right_tree = build_int_cst_type(int_type_tree, 0); - } - else if ((left_type->interface_type() != NULL - && right_type->interface_type() == NULL - && !right_type->is_nil_type()) - || (left_type->interface_type() == NULL - && !left_type->is_nil_type() - && right_type->interface_type() != NULL)) - { - // Comparing an interface value to a non-interface value. - if (left_type->interface_type() == NULL) - { - std::swap(left_type, right_type); - std::swap(left_tree, right_tree); - } - - // The right operand is not an interface. We need to take its - // address if it is not a pointer. - tree make_tmp; - tree arg; - if (right_type->points_to() != NULL) - { - make_tmp = NULL_TREE; - arg = right_tree; - } - else if (TREE_ADDRESSABLE(TREE_TYPE(right_tree)) - || (TREE_CODE(right_tree) != CONST_DECL - && DECL_P(right_tree))) - { - make_tmp = NULL_TREE; - arg = build_fold_addr_expr_loc(location.gcc_location(), right_tree); - if (DECL_P(right_tree)) - TREE_ADDRESSABLE(right_tree) = 1; - } - else - { - tree tmp = create_tmp_var(TREE_TYPE(right_tree), - get_name(right_tree)); - DECL_IGNORED_P(tmp) = 0; - DECL_INITIAL(tmp) = right_tree; - TREE_ADDRESSABLE(tmp) = 1; - make_tmp = build1(DECL_EXPR, void_type_node, tmp); - SET_EXPR_LOCATION(make_tmp, location.gcc_location()); - arg = build_fold_addr_expr_loc(location.gcc_location(), tmp); - } - arg = fold_convert_loc(location.gcc_location(), ptr_type_node, arg); - - tree descriptor = right_type->type_descriptor_pointer(context->gogo(), - location); - - if (left_type->interface_type()->is_empty()) - { - static tree empty_interface_value_compare_decl; - left_tree = Gogo::call_builtin(&empty_interface_value_compare_decl, - location, - "__go_empty_interface_value_compare", - 3, - int_type_tree, - TREE_TYPE(left_tree), - left_tree, - TREE_TYPE(descriptor), - descriptor, - ptr_type_node, - arg); - if (left_tree == error_mark_node) - return error_mark_node; - // This can panic if the type is not comparable. - TREE_NOTHROW(empty_interface_value_compare_decl) = 0; - } - else - { - static tree interface_value_compare_decl; - left_tree = Gogo::call_builtin(&interface_value_compare_decl, - location, - "__go_interface_value_compare", - 3, - int_type_tree, - TREE_TYPE(left_tree), - left_tree, - TREE_TYPE(descriptor), - descriptor, - ptr_type_node, - arg); - if (left_tree == error_mark_node) - return error_mark_node; - // This can panic if the type is not comparable. - TREE_NOTHROW(interface_value_compare_decl) = 0; - } - right_tree = build_int_cst_type(int_type_tree, 0); - - if (make_tmp != NULL_TREE) - left_tree = build2(COMPOUND_EXPR, TREE_TYPE(left_tree), make_tmp, - left_tree); - } - else if (left_type->interface_type() != NULL - && right_type->interface_type() != NULL) - { - if (left_type->interface_type()->is_empty() - && right_type->interface_type()->is_empty()) - { - static tree empty_interface_compare_decl; - left_tree = Gogo::call_builtin(&empty_interface_compare_decl, - location, - "__go_empty_interface_compare", - 2, - int_type_tree, - TREE_TYPE(left_tree), - left_tree, - TREE_TYPE(right_tree), - right_tree); - if (left_tree == error_mark_node) - return error_mark_node; - // This can panic if the type is uncomparable. - TREE_NOTHROW(empty_interface_compare_decl) = 0; - } - else if (!left_type->interface_type()->is_empty() - && !right_type->interface_type()->is_empty()) - { - static tree interface_compare_decl; - left_tree = Gogo::call_builtin(&interface_compare_decl, - location, - "__go_interface_compare", - 2, - int_type_tree, - TREE_TYPE(left_tree), - left_tree, - TREE_TYPE(right_tree), - right_tree); - if (left_tree == error_mark_node) - return error_mark_node; - // This can panic if the type is uncomparable. - TREE_NOTHROW(interface_compare_decl) = 0; - } - else - { - if (left_type->interface_type()->is_empty()) - { - go_assert(op == OPERATOR_EQEQ || op == OPERATOR_NOTEQ); - std::swap(left_type, right_type); - std::swap(left_tree, right_tree); - } - go_assert(!left_type->interface_type()->is_empty()); - go_assert(right_type->interface_type()->is_empty()); - static tree interface_empty_compare_decl; - left_tree = Gogo::call_builtin(&interface_empty_compare_decl, - location, - "__go_interface_empty_compare", - 2, - int_type_tree, - TREE_TYPE(left_tree), - left_tree, - TREE_TYPE(right_tree), - right_tree); - if (left_tree == error_mark_node) - return error_mark_node; - // This can panic if the type is uncomparable. - TREE_NOTHROW(interface_empty_compare_decl) = 0; - } - - right_tree = build_int_cst_type(int_type_tree, 0); - } - - if (left_type->is_nil_type() - && (op == OPERATOR_EQEQ || op == OPERATOR_NOTEQ)) - { - std::swap(left_type, right_type); - std::swap(left_tree, right_tree); - } - - if (right_type->is_nil_type()) - { - if (left_type->array_type() != NULL - && left_type->array_type()->length() == NULL) - { - Array_type* at = left_type->array_type(); - left_tree = at->value_pointer_tree(context->gogo(), left_tree); - right_tree = fold_convert(TREE_TYPE(left_tree), null_pointer_node); - } - else if (left_type->interface_type() != NULL) - { - // An interface is nil if the first field is nil. - tree left_type_tree = TREE_TYPE(left_tree); - go_assert(TREE_CODE(left_type_tree) == RECORD_TYPE); - tree field = TYPE_FIELDS(left_type_tree); - left_tree = build3(COMPONENT_REF, TREE_TYPE(field), left_tree, - field, NULL_TREE); - right_tree = fold_convert(TREE_TYPE(left_tree), null_pointer_node); - } - else - { - go_assert(POINTER_TYPE_P(TREE_TYPE(left_tree))); - right_tree = fold_convert(TREE_TYPE(left_tree), null_pointer_node); - } - } - - if (left_tree == error_mark_node || right_tree == error_mark_node) - return error_mark_node; - - tree result_type_tree; - if (result_type == NULL) - result_type_tree = boolean_type_node; - else - result_type_tree = type_to_tree(result_type->get_backend(context->gogo())); - - tree ret = fold_build2(code, result_type_tree, left_tree, right_tree); - if (CAN_HAVE_LOCATION_P(ret)) - SET_EXPR_LOCATION(ret, location.gcc_location()); - return ret; -} - -// Class Bound_method_expression. - -// Traversal. - -int -Bound_method_expression::do_traverse(Traverse* traverse) -{ - return Expression::traverse(&this->expr_, traverse); -} - -// Return the type of a bound method expression. The type of this -// object is really the type of the method with no receiver. We -// should be able to get away with just returning the type of the -// method. - -Type* -Bound_method_expression::do_type() -{ - if (this->method_->is_function()) - return this->method_->func_value()->type(); - else if (this->method_->is_function_declaration()) - return this->method_->func_declaration_value()->type(); - else - return Type::make_error_type(); -} - -// Determine the types of a method expression. - -void -Bound_method_expression::do_determine_type(const Type_context*) -{ - Function_type* fntype = this->type()->function_type(); - if (fntype == NULL || !fntype->is_method()) - this->expr_->determine_type_no_context(); - else - { - Type_context subcontext(fntype->receiver()->type(), false); - this->expr_->determine_type(&subcontext); - } -} - -// Check the types of a method expression. - -void -Bound_method_expression::do_check_types(Gogo*) -{ - if (!this->method_->is_function() - && !this->method_->is_function_declaration()) - this->report_error(_("object is not a method")); - else - { - Type* rtype = this->type()->function_type()->receiver()->type()->deref(); - Type* etype = (this->expr_type_ != NULL - ? this->expr_type_ - : this->expr_->type()); - etype = etype->deref(); - if (!Type::are_identical(rtype, etype, true, NULL)) - this->report_error(_("method type does not match object type")); - } -} - -// Get the tree for a method expression. There is no standard tree -// representation for this. The only places it may currently be used -// are in a Call_expression or a Go_statement, which will take it -// apart directly. So this has nothing to do at present. - -tree -Bound_method_expression::do_get_tree(Translate_context*) -{ - error_at(this->location(), "reference to method other than calling it"); - return error_mark_node; -} - -// Dump ast representation of a bound method expression. - -void -Bound_method_expression::do_dump_expression(Ast_dump_context* ast_dump_context) - const -{ - if (this->expr_type_ != NULL) - ast_dump_context->ostream() << "("; - ast_dump_context->dump_expression(this->expr_); - if (this->expr_type_ != NULL) - { - ast_dump_context->ostream() << ":"; - ast_dump_context->dump_type(this->expr_type_); - ast_dump_context->ostream() << ")"; - } - - ast_dump_context->ostream() << "." << this->method_->name(); -} - -// Make a method expression. - -Bound_method_expression* -Expression::make_bound_method(Expression* expr, Named_object* method, - Location location) -{ - return new Bound_method_expression(expr, method, location); -} - -// Class Builtin_call_expression. This is used for a call to a -// builtin function. - -class Builtin_call_expression : public Call_expression -{ - public: - Builtin_call_expression(Gogo* gogo, Expression* fn, Expression_list* args, - bool is_varargs, Location location); - - protected: - // This overrides Call_expression::do_lower. - Expression* - do_lower(Gogo*, Named_object*, Statement_inserter*, int); - - bool - do_is_constant() const; - - bool - do_numeric_constant_value(Numeric_constant*) const; - - bool - do_discarding_value(); - - Type* - do_type(); - - void - do_determine_type(const Type_context*); - - void - do_check_types(Gogo*); - - Expression* - do_copy() - { - return new Builtin_call_expression(this->gogo_, this->fn()->copy(), - this->args()->copy(), - this->is_varargs(), - this->location()); - } - - tree - do_get_tree(Translate_context*); - - void - do_export(Export*) const; - - virtual bool - do_is_recover_call() const; - - virtual void - do_set_recover_arg(Expression*); - - private: - // The builtin functions. - enum Builtin_function_code - { - BUILTIN_INVALID, - - // Predeclared builtin functions. - BUILTIN_APPEND, - BUILTIN_CAP, - BUILTIN_CLOSE, - BUILTIN_COMPLEX, - BUILTIN_COPY, - BUILTIN_DELETE, - BUILTIN_IMAG, - BUILTIN_LEN, - BUILTIN_MAKE, - BUILTIN_NEW, - BUILTIN_PANIC, - BUILTIN_PRINT, - BUILTIN_PRINTLN, - BUILTIN_REAL, - BUILTIN_RECOVER, - - // Builtin functions from the unsafe package. - BUILTIN_ALIGNOF, - BUILTIN_OFFSETOF, - BUILTIN_SIZEOF - }; - - Expression* - one_arg() const; - - bool - check_one_arg(); - - static Type* - real_imag_type(Type*); - - static Type* - complex_type(Type*); - - Expression* - lower_make(); - - bool - check_int_value(Expression*, bool is_length); - - // A pointer back to the general IR structure. This avoids a global - // variable, or passing it around everywhere. - Gogo* gogo_; - // The builtin function being called. - Builtin_function_code code_; - // Used to stop endless loops when the length of an array uses len - // or cap of the array itself. - mutable bool seen_; -}; - -Builtin_call_expression::Builtin_call_expression(Gogo* gogo, - Expression* fn, - Expression_list* args, - bool is_varargs, - Location location) - : Call_expression(fn, args, is_varargs, location), - gogo_(gogo), code_(BUILTIN_INVALID), seen_(false) -{ - Func_expression* fnexp = this->fn()->func_expression(); - go_assert(fnexp != NULL); - const std::string& name(fnexp->named_object()->name()); - if (name == "append") - this->code_ = BUILTIN_APPEND; - else if (name == "cap") - this->code_ = BUILTIN_CAP; - else if (name == "close") - this->code_ = BUILTIN_CLOSE; - else if (name == "complex") - this->code_ = BUILTIN_COMPLEX; - else if (name == "copy") - this->code_ = BUILTIN_COPY; - else if (name == "delete") - this->code_ = BUILTIN_DELETE; - else if (name == "imag") - this->code_ = BUILTIN_IMAG; - else if (name == "len") - this->code_ = BUILTIN_LEN; - else if (name == "make") - this->code_ = BUILTIN_MAKE; - else if (name == "new") - this->code_ = BUILTIN_NEW; - else if (name == "panic") - this->code_ = BUILTIN_PANIC; - else if (name == "print") - this->code_ = BUILTIN_PRINT; - else if (name == "println") - this->code_ = BUILTIN_PRINTLN; - else if (name == "real") - this->code_ = BUILTIN_REAL; - else if (name == "recover") - this->code_ = BUILTIN_RECOVER; - else if (name == "Alignof") - this->code_ = BUILTIN_ALIGNOF; - else if (name == "Offsetof") - this->code_ = BUILTIN_OFFSETOF; - else if (name == "Sizeof") - this->code_ = BUILTIN_SIZEOF; - else - go_unreachable(); -} - -// Return whether this is a call to recover. This is a virtual -// function called from the parent class. - -bool -Builtin_call_expression::do_is_recover_call() const -{ - if (this->classification() == EXPRESSION_ERROR) - return false; - return this->code_ == BUILTIN_RECOVER; -} - -// Set the argument for a call to recover. - -void -Builtin_call_expression::do_set_recover_arg(Expression* arg) -{ - const Expression_list* args = this->args(); - go_assert(args == NULL || args->empty()); - Expression_list* new_args = new Expression_list(); - new_args->push_back(arg); - this->set_args(new_args); -} - -// Lower a builtin call expression. This turns new and make into -// specific expressions. We also convert to a constant if we can. - -Expression* -Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function, - Statement_inserter* inserter, int) -{ - if (this->classification() == EXPRESSION_ERROR) - return this; - - Location loc = this->location(); - - if (this->is_varargs() && this->code_ != BUILTIN_APPEND) - { - this->report_error(_("invalid use of %<...%> with builtin function")); - return Expression::make_error(loc); - } - - if (this->is_constant()) - { - Numeric_constant nc; - if (this->numeric_constant_value(&nc)) - return nc.expression(loc); - } - - switch (this->code_) - { - default: - break; - - case BUILTIN_NEW: - { - const Expression_list* args = this->args(); - if (args == NULL || args->size() < 1) - this->report_error(_("not enough arguments")); - else if (args->size() > 1) - this->report_error(_("too many arguments")); - else - { - Expression* arg = args->front(); - if (!arg->is_type_expression()) - { - error_at(arg->location(), "expected type"); - this->set_is_error(); - } - else - return Expression::make_allocation(arg->type(), loc); - } - } - break; - - case BUILTIN_MAKE: - return this->lower_make(); - - case BUILTIN_RECOVER: - if (function != NULL) - function->func_value()->set_calls_recover(); - else - { - // Calling recover outside of a function always returns the - // nil empty interface. - Type* eface = Type::make_empty_interface_type(loc); - return Expression::make_cast(eface, Expression::make_nil(loc), loc); - } - break; - - case BUILTIN_APPEND: - { - // Lower the varargs. - const Expression_list* args = this->args(); - if (args == NULL || args->empty()) - return this; - Type* slice_type = args->front()->type(); - if (!slice_type->is_slice_type()) - { - error_at(args->front()->location(), "argument 1 must be a slice"); - this->set_is_error(); - return this; - } - Type* element_type = slice_type->array_type()->element_type(); - this->lower_varargs(gogo, function, inserter, - Type::make_array_type(element_type, NULL), - 2); - } - break; - - case BUILTIN_DELETE: - { - // Lower to a runtime function call. - const Expression_list* args = this->args(); - if (args == NULL || args->size() < 2) - this->report_error(_("not enough arguments")); - else if (args->size() > 2) - this->report_error(_("too many arguments")); - else if (args->front()->type()->map_type() == NULL) - this->report_error(_("argument 1 must be a map")); - else - { - // Since this function returns no value it must appear in - // a statement by itself, so we don't have to worry about - // order of evaluation of values around it. Evaluate the - // map first to get order of evaluation right. - Map_type* mt = args->front()->type()->map_type(); - Temporary_statement* map_temp = - Statement::make_temporary(mt, args->front(), loc); - inserter->insert(map_temp); - - Temporary_statement* key_temp = - Statement::make_temporary(mt->key_type(), args->back(), loc); - inserter->insert(key_temp); - - Expression* e1 = Expression::make_temporary_reference(map_temp, - loc); - Expression* e2 = Expression::make_temporary_reference(key_temp, - loc); - e2 = Expression::make_unary(OPERATOR_AND, e2, loc); - return Runtime::make_call(Runtime::MAPDELETE, this->location(), - 2, e1, e2); - } - } - break; - } - - return this; -} - -// Lower a make expression. - -Expression* -Builtin_call_expression::lower_make() -{ - Location loc = this->location(); - - const Expression_list* args = this->args(); - if (args == NULL || args->size() < 1) - { - this->report_error(_("not enough arguments")); - return Expression::make_error(this->location()); - } - - Expression_list::const_iterator parg = args->begin(); - - Expression* first_arg = *parg; - if (!first_arg->is_type_expression()) - { - error_at(first_arg->location(), "expected type"); - this->set_is_error(); - return Expression::make_error(this->location()); - } - Type* type = first_arg->type(); - - bool is_slice = false; - bool is_map = false; - bool is_chan = false; - if (type->is_slice_type()) - is_slice = true; - else if (type->map_type() != NULL) - is_map = true; - else if (type->channel_type() != NULL) - is_chan = true; - else - { - this->report_error(_("invalid type for make function")); - return Expression::make_error(this->location()); - } - - bool have_big_args = false; - Type* uintptr_type = Type::lookup_integer_type("uintptr"); - int uintptr_bits = uintptr_type->integer_type()->bits(); - - ++parg; - Expression* len_arg; - if (parg == args->end()) - { - if (is_slice) - { - this->report_error(_("length required when allocating a slice")); - return Expression::make_error(this->location()); - } - - mpz_t zval; - mpz_init_set_ui(zval, 0); - len_arg = Expression::make_integer(&zval, NULL, loc); - mpz_clear(zval); - } - else - { - len_arg = *parg; - if (!this->check_int_value(len_arg, true)) - return Expression::make_error(this->location()); - if (len_arg->type()->integer_type() != NULL - && len_arg->type()->integer_type()->bits() > uintptr_bits) - have_big_args = true; - ++parg; - } - - Expression* cap_arg = NULL; - if (is_slice && parg != args->end()) - { - cap_arg = *parg; - if (!this->check_int_value(cap_arg, false)) - return Expression::make_error(this->location()); - - Numeric_constant nclen; - Numeric_constant nccap; - unsigned long vlen; - unsigned long vcap; - if (len_arg->numeric_constant_value(&nclen) - && cap_arg->numeric_constant_value(&nccap) - && nclen.to_unsigned_long(&vlen) == Numeric_constant::NC_UL_VALID - && nccap.to_unsigned_long(&vcap) == Numeric_constant::NC_UL_VALID - && vlen > vcap) - { - this->report_error(_("len larger than cap")); - return Expression::make_error(this->location()); - } - - if (cap_arg->type()->integer_type() != NULL - && cap_arg->type()->integer_type()->bits() > uintptr_bits) - have_big_args = true; - ++parg; - } - - if (parg != args->end()) - { - this->report_error(_("too many arguments to make")); - return Expression::make_error(this->location()); - } - - Location type_loc = first_arg->location(); - Expression* type_arg; - if (is_slice || is_chan) - type_arg = Expression::make_type_descriptor(type, type_loc); - else if (is_map) - type_arg = Expression::make_map_descriptor(type->map_type(), type_loc); - else - go_unreachable(); - - Expression* call; - if (is_slice) - { - if (cap_arg == NULL) - call = Runtime::make_call((have_big_args - ? Runtime::MAKESLICE1BIG - : Runtime::MAKESLICE1), - loc, 2, type_arg, len_arg); - else - call = Runtime::make_call((have_big_args - ? Runtime::MAKESLICE2BIG - : Runtime::MAKESLICE2), - loc, 3, type_arg, len_arg, cap_arg); - } - else if (is_map) - call = Runtime::make_call((have_big_args - ? Runtime::MAKEMAPBIG - : Runtime::MAKEMAP), - loc, 2, type_arg, len_arg); - else if (is_chan) - call = Runtime::make_call((have_big_args - ? Runtime::MAKECHANBIG - : Runtime::MAKECHAN), - loc, 2, type_arg, len_arg); - else - go_unreachable(); - - return Expression::make_unsafe_cast(type, call, loc); -} - -// Return whether an expression has an integer value. Report an error -// if not. This is used when handling calls to the predeclared make -// function. - -bool -Builtin_call_expression::check_int_value(Expression* e, bool is_length) -{ - Numeric_constant nc; - if (e->numeric_constant_value(&nc)) - { - unsigned long v; - switch (nc.to_unsigned_long(&v)) - { - case Numeric_constant::NC_UL_VALID: - return true; - case Numeric_constant::NC_UL_NOTINT: - error_at(e->location(), "non-integer %s argument to make", - is_length ? "len" : "cap"); - return false; - case Numeric_constant::NC_UL_NEGATIVE: - error_at(e->location(), "negative %s argument to make", - is_length ? "len" : "cap"); - return false; - case Numeric_constant::NC_UL_BIG: - // We don't want to give a compile-time error for a 64-bit - // value on a 32-bit target. - return true; - } - } - - if (e->type()->integer_type() != NULL) - return true; - - error_at(e->location(), "non-integer %s argument to make", - is_length ? "len" : "cap"); - return false; -} - -// Return the type of the real or imag functions, given the type of -// the argument. We need to map complex to float, complex64 to -// float32, and complex128 to float64, so it has to be done by name. -// This returns NULL if it can't figure out the type. - -Type* -Builtin_call_expression::real_imag_type(Type* arg_type) -{ - if (arg_type == NULL || arg_type->is_abstract()) - return NULL; - Named_type* nt = arg_type->named_type(); - if (nt == NULL) - return NULL; - while (nt->real_type()->named_type() != NULL) - nt = nt->real_type()->named_type(); - if (nt->name() == "complex64") - return Type::lookup_float_type("float32"); - else if (nt->name() == "complex128") - return Type::lookup_float_type("float64"); - else - return NULL; -} - -// Return the type of the complex function, given the type of one of the -// argments. Like real_imag_type, we have to map by name. - -Type* -Builtin_call_expression::complex_type(Type* arg_type) -{ - if (arg_type == NULL || arg_type->is_abstract()) - return NULL; - Named_type* nt = arg_type->named_type(); - if (nt == NULL) - return NULL; - while (nt->real_type()->named_type() != NULL) - nt = nt->real_type()->named_type(); - if (nt->name() == "float32") - return Type::lookup_complex_type("complex64"); - else if (nt->name() == "float64") - return Type::lookup_complex_type("complex128"); - else - return NULL; -} - -// Return a single argument, or NULL if there isn't one. - -Expression* -Builtin_call_expression::one_arg() const -{ - const Expression_list* args = this->args(); - if (args == NULL || args->size() != 1) - return NULL; - return args->front(); -} - -// A traversal class which looks for a call or receive expression. - -class Find_call_expression : public Traverse -{ - public: - Find_call_expression() - : Traverse(traverse_expressions), - found_(false) - { } - - int - expression(Expression**); - - bool - found() - { return this->found_; } - - private: - bool found_; -}; - -int -Find_call_expression::expression(Expression** pexpr) -{ - if ((*pexpr)->call_expression() != NULL - || (*pexpr)->receive_expression() != NULL) - { - this->found_ = true; - return TRAVERSE_EXIT; - } - return TRAVERSE_CONTINUE; -} - -// Return whether this is constant: len of a string constant, or len -// or cap of an array, or unsafe.Sizeof, unsafe.Offsetof, -// unsafe.Alignof. - -bool -Builtin_call_expression::do_is_constant() const -{ - switch (this->code_) - { - case BUILTIN_LEN: - case BUILTIN_CAP: - { - if (this->seen_) - return false; - - Expression* arg = this->one_arg(); - if (arg == NULL) - return false; - Type* arg_type = arg->type(); - - if (arg_type->points_to() != NULL - && arg_type->points_to()->array_type() != NULL - && !arg_type->points_to()->is_slice_type()) - arg_type = arg_type->points_to(); - - // The len and cap functions are only constant if there are no - // function calls or channel operations in the arguments. - // Otherwise we have to make the call. - if (!arg->is_constant()) - { - Find_call_expression find_call; - Expression::traverse(&arg, &find_call); - if (find_call.found()) - return false; - } - - if (arg_type->array_type() != NULL - && arg_type->array_type()->length() != NULL) - return true; - - if (this->code_ == BUILTIN_LEN && arg_type->is_string_type()) - { - this->seen_ = true; - bool ret = arg->is_constant(); - this->seen_ = false; - return ret; - } - } - break; - - case BUILTIN_SIZEOF: - case BUILTIN_ALIGNOF: - return this->one_arg() != NULL; - - case BUILTIN_OFFSETOF: - { - Expression* arg = this->one_arg(); - if (arg == NULL) - return false; - return arg->field_reference_expression() != NULL; - } - - case BUILTIN_COMPLEX: - { - const Expression_list* args = this->args(); - if (args != NULL && args->size() == 2) - return args->front()->is_constant() && args->back()->is_constant(); - } - break; - - case BUILTIN_REAL: - case BUILTIN_IMAG: - { - Expression* arg = this->one_arg(); - return arg != NULL && arg->is_constant(); - } - - default: - break; - } - - return false; -} - -// Return a numeric constant if possible. - -bool -Builtin_call_expression::do_numeric_constant_value(Numeric_constant* nc) const -{ - if (this->code_ == BUILTIN_LEN - || this->code_ == BUILTIN_CAP) - { - Expression* arg = this->one_arg(); - if (arg == NULL) - return false; - Type* arg_type = arg->type(); - - if (this->code_ == BUILTIN_LEN && arg_type->is_string_type()) - { - std::string sval; - if (arg->string_constant_value(&sval)) - { - nc->set_unsigned_long(Type::lookup_integer_type("int"), - sval.length()); - return true; - } - } - - if (arg_type->points_to() != NULL - && arg_type->points_to()->array_type() != NULL - && !arg_type->points_to()->is_slice_type()) - arg_type = arg_type->points_to(); - - if (arg_type->array_type() != NULL - && arg_type->array_type()->length() != NULL) - { - if (this->seen_) - return false; - Expression* e = arg_type->array_type()->length(); - this->seen_ = true; - bool r = e->numeric_constant_value(nc); - this->seen_ = false; - if (r) - { - if (!nc->set_type(Type::lookup_integer_type("int"), false, - this->location())) - r = false; - } - return r; - } - } - else if (this->code_ == BUILTIN_SIZEOF - || this->code_ == BUILTIN_ALIGNOF) - { - Expression* arg = this->one_arg(); - if (arg == NULL) - return false; - Type* arg_type = arg->type(); - if (arg_type->is_error()) - return false; - if (arg_type->is_abstract()) - return false; - if (arg_type->named_type() != NULL) - arg_type->named_type()->convert(this->gogo_); - - unsigned int ret; - if (this->code_ == BUILTIN_SIZEOF) - { - if (!arg_type->backend_type_size(this->gogo_, &ret)) - return false; - } - else if (this->code_ == BUILTIN_ALIGNOF) - { - if (arg->field_reference_expression() == NULL) - { - if (!arg_type->backend_type_align(this->gogo_, &ret)) - return false; - } - else - { - // Calling unsafe.Alignof(s.f) returns the alignment of - // the type of f when it is used as a field in a struct. - if (!arg_type->backend_type_field_align(this->gogo_, &ret)) - return false; - } - } - else - go_unreachable(); - - nc->set_unsigned_long(Type::lookup_integer_type("uintptr"), - static_cast<unsigned long>(ret)); - return true; - } - else if (this->code_ == BUILTIN_OFFSETOF) - { - Expression* arg = this->one_arg(); - if (arg == NULL) - return false; - Field_reference_expression* farg = arg->field_reference_expression(); - if (farg == NULL) - return false; - Expression* struct_expr = farg->expr(); - Type* st = struct_expr->type(); - if (st->struct_type() == NULL) - return false; - if (st->named_type() != NULL) - st->named_type()->convert(this->gogo_); - unsigned int offset; - if (!st->struct_type()->backend_field_offset(this->gogo_, - farg->field_index(), - &offset)) - return false; - nc->set_unsigned_long(Type::lookup_integer_type("uintptr"), - static_cast<unsigned long>(offset)); - return true; - } - else if (this->code_ == BUILTIN_REAL || this->code_ == BUILTIN_IMAG) - { - Expression* arg = this->one_arg(); - if (arg == NULL) - return false; - - Numeric_constant argnc; - if (!arg->numeric_constant_value(&argnc)) - return false; - - mpfr_t real; - mpfr_t imag; - if (!argnc.to_complex(&real, &imag)) - return false; - - Type* type = Builtin_call_expression::real_imag_type(argnc.type()); - if (this->code_ == BUILTIN_REAL) - nc->set_float(type, real); - else - nc->set_float(type, imag); - return true; - } - else if (this->code_ == BUILTIN_COMPLEX) - { - const Expression_list* args = this->args(); - if (args == NULL || args->size() != 2) - return false; - - Numeric_constant rnc; - if (!args->front()->numeric_constant_value(&rnc)) - return false; - Numeric_constant inc; - if (!args->back()->numeric_constant_value(&inc)) - return false; - - if (rnc.type() != NULL - && !rnc.type()->is_abstract() - && inc.type() != NULL - && !inc.type()->is_abstract() - && !Type::are_identical(rnc.type(), inc.type(), false, NULL)) - return false; - - mpfr_t r; - if (!rnc.to_float(&r)) - return false; - mpfr_t i; - if (!inc.to_float(&i)) - { - mpfr_clear(r); - return false; - } - - Type* arg_type = rnc.type(); - if (arg_type == NULL || arg_type->is_abstract()) - arg_type = inc.type(); - - Type* type = Builtin_call_expression::complex_type(arg_type); - nc->set_complex(type, r, i); - - mpfr_clear(r); - mpfr_clear(i); - - return true; - } - - return false; -} - -// Give an error if we are discarding the value of an expression which -// should not normally be discarded. We don't give an error for -// discarding the value of an ordinary function call, but we do for -// builtin functions, purely for consistency with the gc compiler. - -bool -Builtin_call_expression::do_discarding_value() -{ - switch (this->code_) - { - case BUILTIN_INVALID: - default: - go_unreachable(); - - case BUILTIN_APPEND: - case BUILTIN_CAP: - case BUILTIN_COMPLEX: - case BUILTIN_IMAG: - case BUILTIN_LEN: - case BUILTIN_MAKE: - case BUILTIN_NEW: - case BUILTIN_REAL: - case BUILTIN_ALIGNOF: - case BUILTIN_OFFSETOF: - case BUILTIN_SIZEOF: - this->unused_value_error(); - return false; - - case BUILTIN_CLOSE: - case BUILTIN_COPY: - case BUILTIN_DELETE: - case BUILTIN_PANIC: - case BUILTIN_PRINT: - case BUILTIN_PRINTLN: - case BUILTIN_RECOVER: - return true; - } -} - -// Return the type. - -Type* -Builtin_call_expression::do_type() -{ - switch (this->code_) - { - case BUILTIN_INVALID: - default: - go_unreachable(); - - case BUILTIN_NEW: - case BUILTIN_MAKE: - { - const Expression_list* args = this->args(); - if (args == NULL || args->empty()) - return Type::make_error_type(); - return Type::make_pointer_type(args->front()->type()); - } - - case BUILTIN_CAP: - case BUILTIN_COPY: - case BUILTIN_LEN: - return Type::lookup_integer_type("int"); - - case BUILTIN_ALIGNOF: - case BUILTIN_OFFSETOF: - case BUILTIN_SIZEOF: - return Type::lookup_integer_type("uintptr"); - - case BUILTIN_CLOSE: - case BUILTIN_DELETE: - case BUILTIN_PANIC: - case BUILTIN_PRINT: - case BUILTIN_PRINTLN: - return Type::make_void_type(); - - case BUILTIN_RECOVER: - return Type::make_empty_interface_type(Linemap::predeclared_location()); - - case BUILTIN_APPEND: - { - const Expression_list* args = this->args(); - if (args == NULL || args->empty()) - return Type::make_error_type(); - return args->front()->type(); - } - - case BUILTIN_REAL: - case BUILTIN_IMAG: - { - Expression* arg = this->one_arg(); - if (arg == NULL) - return Type::make_error_type(); - Type* t = arg->type(); - if (t->is_abstract()) - t = t->make_non_abstract_type(); - t = Builtin_call_expression::real_imag_type(t); - if (t == NULL) - t = Type::make_error_type(); - return t; - } - - case BUILTIN_COMPLEX: - { - const Expression_list* args = this->args(); - if (args == NULL || args->size() != 2) - return Type::make_error_type(); - Type* t = args->front()->type(); - if (t->is_abstract()) - { - t = args->back()->type(); - if (t->is_abstract()) - t = t->make_non_abstract_type(); - } - t = Builtin_call_expression::complex_type(t); - if (t == NULL) - t = Type::make_error_type(); - return t; - } - } -} - -// Determine the type. - -void -Builtin_call_expression::do_determine_type(const Type_context* context) -{ - if (!this->determining_types()) - return; - - this->fn()->determine_type_no_context(); - - const Expression_list* args = this->args(); - - bool is_print; - Type* arg_type = NULL; - switch (this->code_) - { - case BUILTIN_PRINT: - case BUILTIN_PRINTLN: - // Do not force a large integer constant to "int". - is_print = true; - break; - - case BUILTIN_REAL: - case BUILTIN_IMAG: - arg_type = Builtin_call_expression::complex_type(context->type); - is_print = false; - break; - - case BUILTIN_COMPLEX: - { - // For the complex function the type of one operand can - // determine the type of the other, as in a binary expression. - arg_type = Builtin_call_expression::real_imag_type(context->type); - if (args != NULL && args->size() == 2) - { - Type* t1 = args->front()->type(); - Type* t2 = args->back()->type(); - if (!t1->is_abstract()) - arg_type = t1; - else if (!t2->is_abstract()) - arg_type = t2; - } - is_print = false; - } - break; - - default: - is_print = false; - break; - } - - if (args != NULL) - { - for (Expression_list::const_iterator pa = args->begin(); - pa != args->end(); - ++pa) - { - Type_context subcontext; - subcontext.type = arg_type; - - if (is_print) - { - // We want to print large constants, we so can't just - // use the appropriate nonabstract type. Use uint64 for - // an integer if we know it is nonnegative, otherwise - // use int64 for a integer, otherwise use float64 for a - // float or complex128 for a complex. - Type* want_type = NULL; - Type* atype = (*pa)->type(); - if (atype->is_abstract()) - { - if (atype->integer_type() != NULL) - { - Numeric_constant nc; - if (this->numeric_constant_value(&nc)) - { - mpz_t val; - if (nc.to_int(&val)) - { - if (mpz_sgn(val) >= 0) - want_type = Type::lookup_integer_type("uint64"); - mpz_clear(val); - } - } - if (want_type == NULL) - want_type = Type::lookup_integer_type("int64"); - } - else if (atype->float_type() != NULL) - want_type = Type::lookup_float_type("float64"); - else if (atype->complex_type() != NULL) - want_type = Type::lookup_complex_type("complex128"); - else if (atype->is_abstract_string_type()) - want_type = Type::lookup_string_type(); - else if (atype->is_abstract_boolean_type()) - want_type = Type::lookup_bool_type(); - else - go_unreachable(); - subcontext.type = want_type; - } - } - - (*pa)->determine_type(&subcontext); - } - } -} - -// If there is exactly one argument, return true. Otherwise give an -// error message and return false. - -bool -Builtin_call_expression::check_one_arg() -{ - const Expression_list* args = this->args(); - if (args == NULL || args->size() < 1) - { - this->report_error(_("not enough arguments")); - return false; - } - else if (args->size() > 1) - { - this->report_error(_("too many arguments")); - return false; - } - if (args->front()->is_error_expression() - || args->front()->type()->is_error()) - { - this->set_is_error(); - return false; - } - return true; -} - -// Check argument types for a builtin function. - -void -Builtin_call_expression::do_check_types(Gogo*) -{ - if (this->is_error_expression()) - return; - switch (this->code_) - { - case BUILTIN_INVALID: - case BUILTIN_NEW: - case BUILTIN_MAKE: - case BUILTIN_DELETE: - return; - - case BUILTIN_LEN: - case BUILTIN_CAP: - { - // The single argument may be either a string or an array or a - // map or a channel, or a pointer to a closed array. - if (this->check_one_arg()) - { - Type* arg_type = this->one_arg()->type(); - if (arg_type->points_to() != NULL - && arg_type->points_to()->array_type() != NULL - && !arg_type->points_to()->is_slice_type()) - arg_type = arg_type->points_to(); - if (this->code_ == BUILTIN_CAP) - { - if (!arg_type->is_error() - && arg_type->array_type() == NULL - && arg_type->channel_type() == NULL) - this->report_error(_("argument must be array or slice " - "or channel")); - } - else - { - if (!arg_type->is_error() - && !arg_type->is_string_type() - && arg_type->array_type() == NULL - && arg_type->map_type() == NULL - && arg_type->channel_type() == NULL) - this->report_error(_("argument must be string or " - "array or slice or map or channel")); - } - } - } - break; - - case BUILTIN_PRINT: - case BUILTIN_PRINTLN: - { - const Expression_list* args = this->args(); - if (args == NULL) - { - if (this->code_ == BUILTIN_PRINT) - warning_at(this->location(), 0, - "no arguments for builtin function %<%s%>", - (this->code_ == BUILTIN_PRINT - ? "print" - : "println")); - } - else - { - for (Expression_list::const_iterator p = args->begin(); - p != args->end(); - ++p) - { - Type* type = (*p)->type(); - if (type->is_error() - || type->is_string_type() - || type->integer_type() != NULL - || type->float_type() != NULL - || type->complex_type() != NULL - || type->is_boolean_type() - || type->points_to() != NULL - || type->interface_type() != NULL - || type->channel_type() != NULL - || type->map_type() != NULL - || type->function_type() != NULL - || type->is_slice_type()) - ; - else if ((*p)->is_type_expression()) - { - // If this is a type expression it's going to give - // an error anyhow, so we don't need one here. - } - else - this->report_error(_("unsupported argument type to " - "builtin function")); - } - } - } - break; - - case BUILTIN_CLOSE: - if (this->check_one_arg()) - { - if (this->one_arg()->type()->channel_type() == NULL) - this->report_error(_("argument must be channel")); - else if (!this->one_arg()->type()->channel_type()->may_send()) - this->report_error(_("cannot close receive-only channel")); - } - break; - - case BUILTIN_PANIC: - case BUILTIN_SIZEOF: - case BUILTIN_ALIGNOF: - this->check_one_arg(); - break; - - case BUILTIN_RECOVER: - if (this->args() != NULL && !this->args()->empty()) - this->report_error(_("too many arguments")); - break; - - case BUILTIN_OFFSETOF: - if (this->check_one_arg()) - { - Expression* arg = this->one_arg(); - if (arg->field_reference_expression() == NULL) - this->report_error(_("argument must be a field reference")); - } - break; - - case BUILTIN_COPY: - { - const Expression_list* args = this->args(); - if (args == NULL || args->size() < 2) - { - this->report_error(_("not enough arguments")); - break; - } - else if (args->size() > 2) - { - this->report_error(_("too many arguments")); - break; - } - Type* arg1_type = args->front()->type(); - Type* arg2_type = args->back()->type(); - if (arg1_type->is_error() || arg2_type->is_error()) - break; - - Type* e1; - if (arg1_type->is_slice_type()) - e1 = arg1_type->array_type()->element_type(); - else - { - this->report_error(_("left argument must be a slice")); - break; - } - - if (arg2_type->is_slice_type()) - { - Type* e2 = arg2_type->array_type()->element_type(); - if (!Type::are_identical(e1, e2, true, NULL)) - this->report_error(_("element types must be the same")); - } - else if (arg2_type->is_string_type()) - { - if (e1->integer_type() == NULL || !e1->integer_type()->is_byte()) - this->report_error(_("first argument must be []byte")); - } - else - this->report_error(_("second argument must be slice or string")); - } - break; - - case BUILTIN_APPEND: - { - const Expression_list* args = this->args(); - if (args == NULL || args->size() < 2) - { - this->report_error(_("not enough arguments")); - break; - } - if (args->size() > 2) - { - this->report_error(_("too many arguments")); - break; - } - if (args->front()->type()->is_error() - || args->back()->type()->is_error()) - break; - - Array_type* at = args->front()->type()->array_type(); - Type* e = at->element_type(); - - // The language permits appending a string to a []byte, as a - // special case. - if (args->back()->type()->is_string_type()) - { - if (e->integer_type() != NULL && e->integer_type()->is_byte()) - break; - } - - // The language says that the second argument must be - // assignable to a slice of the element type of the first - // argument. We already know the first argument is a slice - // type. - Type* arg2_type = Type::make_array_type(e, NULL); - std::string reason; - if (!Type::are_assignable(arg2_type, args->back()->type(), &reason)) - { - if (reason.empty()) - this->report_error(_("argument 2 has invalid type")); - else - { - error_at(this->location(), "argument 2 has invalid type (%s)", - reason.c_str()); - this->set_is_error(); - } - } - break; - } - - case BUILTIN_REAL: - case BUILTIN_IMAG: - if (this->check_one_arg()) - { - if (this->one_arg()->type()->complex_type() == NULL) - this->report_error(_("argument must have complex type")); - } - break; - - case BUILTIN_COMPLEX: - { - const Expression_list* args = this->args(); - if (args == NULL || args->size() < 2) - this->report_error(_("not enough arguments")); - else if (args->size() > 2) - this->report_error(_("too many arguments")); - else if (args->front()->is_error_expression() - || args->front()->type()->is_error() - || args->back()->is_error_expression() - || args->back()->type()->is_error()) - this->set_is_error(); - else if (!Type::are_identical(args->front()->type(), - args->back()->type(), true, NULL)) - this->report_error(_("complex arguments must have identical types")); - else if (args->front()->type()->float_type() == NULL) - this->report_error(_("complex arguments must have " - "floating-point type")); - } - break; - - default: - go_unreachable(); - } -} - -// Return the tree for a builtin function. - -tree -Builtin_call_expression::do_get_tree(Translate_context* context) -{ - Gogo* gogo = context->gogo(); - Location location = this->location(); - switch (this->code_) - { - case BUILTIN_INVALID: - case BUILTIN_NEW: - case BUILTIN_MAKE: - go_unreachable(); - - case BUILTIN_LEN: - case BUILTIN_CAP: - { - const Expression_list* args = this->args(); - go_assert(args != NULL && args->size() == 1); - Expression* arg = *args->begin(); - Type* arg_type = arg->type(); - - if (this->seen_) - { - go_assert(saw_errors()); - return error_mark_node; - } - this->seen_ = true; - - tree arg_tree = arg->get_tree(context); - - this->seen_ = false; - - if (arg_tree == error_mark_node) - return error_mark_node; - - if (arg_type->points_to() != NULL) - { - arg_type = arg_type->points_to(); - go_assert(arg_type->array_type() != NULL - && !arg_type->is_slice_type()); - go_assert(POINTER_TYPE_P(TREE_TYPE(arg_tree))); - arg_tree = build_fold_indirect_ref(arg_tree); - } - - Type* int_type = Type::lookup_integer_type("int"); - tree int_type_tree = type_to_tree(int_type->get_backend(gogo)); - - tree val_tree; - if (this->code_ == BUILTIN_LEN) - { - if (arg_type->is_string_type()) - val_tree = String_type::length_tree(gogo, arg_tree); - else if (arg_type->array_type() != NULL) - { - if (this->seen_) - { - go_assert(saw_errors()); - return error_mark_node; - } - this->seen_ = true; - val_tree = arg_type->array_type()->length_tree(gogo, arg_tree); - this->seen_ = false; - } - else if (arg_type->map_type() != NULL) - { - tree arg_type_tree = type_to_tree(arg_type->get_backend(gogo)); - static tree map_len_fndecl; - val_tree = Gogo::call_builtin(&map_len_fndecl, - location, - "__go_map_len", - 1, - int_type_tree, - arg_type_tree, - arg_tree); - } - else if (arg_type->channel_type() != NULL) - { - tree arg_type_tree = type_to_tree(arg_type->get_backend(gogo)); - static tree chan_len_fndecl; - val_tree = Gogo::call_builtin(&chan_len_fndecl, - location, - "__go_chan_len", - 1, - int_type_tree, - arg_type_tree, - arg_tree); - } - else - go_unreachable(); - } - else - { - if (arg_type->array_type() != NULL) - { - if (this->seen_) - { - go_assert(saw_errors()); - return error_mark_node; - } - this->seen_ = true; - val_tree = arg_type->array_type()->capacity_tree(gogo, - arg_tree); - this->seen_ = false; - } - else if (arg_type->channel_type() != NULL) - { - tree arg_type_tree = type_to_tree(arg_type->get_backend(gogo)); - static tree chan_cap_fndecl; - val_tree = Gogo::call_builtin(&chan_cap_fndecl, - location, - "__go_chan_cap", - 1, - int_type_tree, - arg_type_tree, - arg_tree); - } - else - go_unreachable(); - } - - return fold_convert_loc(location.gcc_location(), int_type_tree, - val_tree); - } - - case BUILTIN_PRINT: - case BUILTIN_PRINTLN: - { - const bool is_ln = this->code_ == BUILTIN_PRINTLN; - tree stmt_list = NULL_TREE; - - const Expression_list* call_args = this->args(); - if (call_args != NULL) - { - for (Expression_list::const_iterator p = call_args->begin(); - p != call_args->end(); - ++p) - { - if (is_ln && p != call_args->begin()) - { - static tree print_space_fndecl; - tree call = Gogo::call_builtin(&print_space_fndecl, - location, - "__go_print_space", - 0, - void_type_node); - if (call == error_mark_node) - return error_mark_node; - append_to_statement_list(call, &stmt_list); - } - - Type* type = (*p)->type(); - - tree arg = (*p)->get_tree(context); - if (arg == error_mark_node) - return error_mark_node; - - tree* pfndecl; - const char* fnname; - if (type->is_string_type()) - { - static tree print_string_fndecl; - pfndecl = &print_string_fndecl; - fnname = "__go_print_string"; - } - else if (type->integer_type() != NULL - && type->integer_type()->is_unsigned()) - { - static tree print_uint64_fndecl; - pfndecl = &print_uint64_fndecl; - fnname = "__go_print_uint64"; - Type* itype = Type::lookup_integer_type("uint64"); - Btype* bitype = itype->get_backend(gogo); - arg = fold_convert_loc(location.gcc_location(), - type_to_tree(bitype), arg); - } - else if (type->integer_type() != NULL) - { - static tree print_int64_fndecl; - pfndecl = &print_int64_fndecl; - fnname = "__go_print_int64"; - Type* itype = Type::lookup_integer_type("int64"); - Btype* bitype = itype->get_backend(gogo); - arg = fold_convert_loc(location.gcc_location(), - type_to_tree(bitype), arg); - } - else if (type->float_type() != NULL) - { - static tree print_double_fndecl; - pfndecl = &print_double_fndecl; - fnname = "__go_print_double"; - arg = fold_convert_loc(location.gcc_location(), - double_type_node, arg); - } - else if (type->complex_type() != NULL) - { - static tree print_complex_fndecl; - pfndecl = &print_complex_fndecl; - fnname = "__go_print_complex"; - arg = fold_convert_loc(location.gcc_location(), - complex_double_type_node, arg); - } - else if (type->is_boolean_type()) - { - static tree print_bool_fndecl; - pfndecl = &print_bool_fndecl; - fnname = "__go_print_bool"; - } - else if (type->points_to() != NULL - || type->channel_type() != NULL - || type->map_type() != NULL - || type->function_type() != NULL) - { - static tree print_pointer_fndecl; - pfndecl = &print_pointer_fndecl; - fnname = "__go_print_pointer"; - arg = fold_convert_loc(location.gcc_location(), - ptr_type_node, arg); - } - else if (type->interface_type() != NULL) - { - if (type->interface_type()->is_empty()) - { - static tree print_empty_interface_fndecl; - pfndecl = &print_empty_interface_fndecl; - fnname = "__go_print_empty_interface"; - } - else - { - static tree print_interface_fndecl; - pfndecl = &print_interface_fndecl; - fnname = "__go_print_interface"; - } - } - else if (type->is_slice_type()) - { - static tree print_slice_fndecl; - pfndecl = &print_slice_fndecl; - fnname = "__go_print_slice"; - } - else - { - go_assert(saw_errors()); - return error_mark_node; - } - - tree call = Gogo::call_builtin(pfndecl, - location, - fnname, - 1, - void_type_node, - TREE_TYPE(arg), - arg); - if (call == error_mark_node) - return error_mark_node; - append_to_statement_list(call, &stmt_list); - } - } - - if (is_ln) - { - static tree print_nl_fndecl; - tree call = Gogo::call_builtin(&print_nl_fndecl, - location, - "__go_print_nl", - 0, - void_type_node); - if (call == error_mark_node) - return error_mark_node; - append_to_statement_list(call, &stmt_list); - } - - return stmt_list; - } - - case BUILTIN_PANIC: - { - const Expression_list* args = this->args(); - go_assert(args != NULL && args->size() == 1); - Expression* arg = args->front(); - tree arg_tree = arg->get_tree(context); - if (arg_tree == error_mark_node) - return error_mark_node; - Type *empty = - Type::make_empty_interface_type(Linemap::predeclared_location()); - arg_tree = Expression::convert_for_assignment(context, empty, - arg->type(), - arg_tree, location); - static tree panic_fndecl; - tree call = Gogo::call_builtin(&panic_fndecl, - location, - "__go_panic", - 1, - void_type_node, - TREE_TYPE(arg_tree), - arg_tree); - if (call == error_mark_node) - return error_mark_node; - // This function will throw an exception. - TREE_NOTHROW(panic_fndecl) = 0; - // This function will not return. - TREE_THIS_VOLATILE(panic_fndecl) = 1; - return call; - } - - case BUILTIN_RECOVER: - { - // The argument is set when building recover thunks. It's a - // boolean value which is true if we can recover a value now. - const Expression_list* args = this->args(); - go_assert(args != NULL && args->size() == 1); - Expression* arg = args->front(); - tree arg_tree = arg->get_tree(context); - if (arg_tree == error_mark_node) - return error_mark_node; - - Type *empty = - Type::make_empty_interface_type(Linemap::predeclared_location()); - tree empty_tree = type_to_tree(empty->get_backend(context->gogo())); - - Type* nil_type = Type::make_nil_type(); - Expression* nil = Expression::make_nil(location); - tree nil_tree = nil->get_tree(context); - tree empty_nil_tree = Expression::convert_for_assignment(context, - empty, - nil_type, - nil_tree, - location); - - // We need to handle a deferred call to recover specially, - // because it changes whether it can recover a panic or not. - // See test7 in test/recover1.go. - tree call; - if (this->is_deferred()) - { - static tree deferred_recover_fndecl; - call = Gogo::call_builtin(&deferred_recover_fndecl, - location, - "__go_deferred_recover", - 0, - empty_tree); - } - else - { - static tree recover_fndecl; - call = Gogo::call_builtin(&recover_fndecl, - location, - "__go_recover", - 0, - empty_tree); - } - if (call == error_mark_node) - return error_mark_node; - return fold_build3_loc(location.gcc_location(), COND_EXPR, empty_tree, - arg_tree, call, empty_nil_tree); - } - - case BUILTIN_CLOSE: - { - const Expression_list* args = this->args(); - go_assert(args != NULL && args->size() == 1); - Expression* arg = args->front(); - tree arg_tree = arg->get_tree(context); - if (arg_tree == error_mark_node) - return error_mark_node; - static tree close_fndecl; - return Gogo::call_builtin(&close_fndecl, - location, - "__go_builtin_close", - 1, - void_type_node, - TREE_TYPE(arg_tree), - arg_tree); - } - - case BUILTIN_SIZEOF: - case BUILTIN_OFFSETOF: - case BUILTIN_ALIGNOF: - { - Numeric_constant nc; - unsigned long val; - if (!this->numeric_constant_value(&nc) - || nc.to_unsigned_long(&val) != Numeric_constant::NC_UL_VALID) - { - go_assert(saw_errors()); - return error_mark_node; - } - Type* uintptr_type = Type::lookup_integer_type("uintptr"); - tree type = type_to_tree(uintptr_type->get_backend(gogo)); - return build_int_cst(type, val); - } - - case BUILTIN_COPY: - { - const Expression_list* args = this->args(); - go_assert(args != NULL && args->size() == 2); - Expression* arg1 = args->front(); - Expression* arg2 = args->back(); - - tree arg1_tree = arg1->get_tree(context); - tree arg2_tree = arg2->get_tree(context); - if (arg1_tree == error_mark_node || arg2_tree == error_mark_node) - return error_mark_node; - - Type* arg1_type = arg1->type(); - Array_type* at = arg1_type->array_type(); - arg1_tree = save_expr(arg1_tree); - tree arg1_val = at->value_pointer_tree(gogo, arg1_tree); - tree arg1_len = at->length_tree(gogo, arg1_tree); - if (arg1_val == error_mark_node || arg1_len == error_mark_node) - return error_mark_node; - - Type* arg2_type = arg2->type(); - tree arg2_val; - tree arg2_len; - if (arg2_type->is_slice_type()) - { - at = arg2_type->array_type(); - arg2_tree = save_expr(arg2_tree); - arg2_val = at->value_pointer_tree(gogo, arg2_tree); - arg2_len = at->length_tree(gogo, arg2_tree); - } - else - { - arg2_tree = save_expr(arg2_tree); - arg2_val = String_type::bytes_tree(gogo, arg2_tree); - arg2_len = String_type::length_tree(gogo, arg2_tree); - } - if (arg2_val == error_mark_node || arg2_len == error_mark_node) - return error_mark_node; - - arg1_len = save_expr(arg1_len); - arg2_len = save_expr(arg2_len); - tree len = fold_build3_loc(location.gcc_location(), COND_EXPR, - TREE_TYPE(arg1_len), - fold_build2_loc(location.gcc_location(), - LT_EXPR, boolean_type_node, - arg1_len, arg2_len), - arg1_len, arg2_len); - len = save_expr(len); - - Type* element_type = at->element_type(); - Btype* element_btype = element_type->get_backend(gogo); - tree element_type_tree = type_to_tree(element_btype); - if (element_type_tree == error_mark_node) - return error_mark_node; - tree element_size = TYPE_SIZE_UNIT(element_type_tree); - tree bytecount = fold_convert_loc(location.gcc_location(), - TREE_TYPE(element_size), len); - bytecount = fold_build2_loc(location.gcc_location(), MULT_EXPR, - TREE_TYPE(element_size), - bytecount, element_size); - bytecount = fold_convert_loc(location.gcc_location(), size_type_node, - bytecount); - - arg1_val = fold_convert_loc(location.gcc_location(), ptr_type_node, - arg1_val); - arg2_val = fold_convert_loc(location.gcc_location(), ptr_type_node, - arg2_val); - - static tree copy_fndecl; - tree call = Gogo::call_builtin(©_fndecl, - location, - "__go_copy", - 3, - void_type_node, - ptr_type_node, - arg1_val, - ptr_type_node, - arg2_val, - size_type_node, - bytecount); - if (call == error_mark_node) - return error_mark_node; - - return fold_build2_loc(location.gcc_location(), COMPOUND_EXPR, - TREE_TYPE(len), call, len); - } - - case BUILTIN_APPEND: - { - const Expression_list* args = this->args(); - go_assert(args != NULL && args->size() == 2); - Expression* arg1 = args->front(); - Expression* arg2 = args->back(); - - tree arg1_tree = arg1->get_tree(context); - tree arg2_tree = arg2->get_tree(context); - if (arg1_tree == error_mark_node || arg2_tree == error_mark_node) - return error_mark_node; - - Array_type* at = arg1->type()->array_type(); - Type* element_type = at->element_type()->forwarded(); - - tree arg2_val; - tree arg2_len; - tree element_size; - if (arg2->type()->is_string_type() - && element_type->integer_type() != NULL - && element_type->integer_type()->is_byte()) - { - arg2_tree = save_expr(arg2_tree); - arg2_val = String_type::bytes_tree(gogo, arg2_tree); - arg2_len = String_type::length_tree(gogo, arg2_tree); - element_size = size_int(1); - } - else - { - arg2_tree = Expression::convert_for_assignment(context, at, - arg2->type(), - arg2_tree, - location); - if (arg2_tree == error_mark_node) - return error_mark_node; - - arg2_tree = save_expr(arg2_tree); - - arg2_val = at->value_pointer_tree(gogo, arg2_tree); - arg2_len = at->length_tree(gogo, arg2_tree); - - Btype* element_btype = element_type->get_backend(gogo); - tree element_type_tree = type_to_tree(element_btype); - if (element_type_tree == error_mark_node) - return error_mark_node; - element_size = TYPE_SIZE_UNIT(element_type_tree); - } - - arg2_val = fold_convert_loc(location.gcc_location(), ptr_type_node, - arg2_val); - arg2_len = fold_convert_loc(location.gcc_location(), size_type_node, - arg2_len); - element_size = fold_convert_loc(location.gcc_location(), size_type_node, - element_size); - - if (arg2_val == error_mark_node - || arg2_len == error_mark_node - || element_size == error_mark_node) - return error_mark_node; - - // We rebuild the decl each time since the slice types may - // change. - tree append_fndecl = NULL_TREE; - return Gogo::call_builtin(&append_fndecl, - location, - "__go_append", - 4, - TREE_TYPE(arg1_tree), - TREE_TYPE(arg1_tree), - arg1_tree, - ptr_type_node, - arg2_val, - size_type_node, - arg2_len, - size_type_node, - element_size); - } - - case BUILTIN_REAL: - case BUILTIN_IMAG: - { - const Expression_list* args = this->args(); - go_assert(args != NULL && args->size() == 1); - Expression* arg = args->front(); - tree arg_tree = arg->get_tree(context); - if (arg_tree == error_mark_node) - return error_mark_node; - go_assert(COMPLEX_FLOAT_TYPE_P(TREE_TYPE(arg_tree))); - if (this->code_ == BUILTIN_REAL) - return fold_build1_loc(location.gcc_location(), REALPART_EXPR, - TREE_TYPE(TREE_TYPE(arg_tree)), - arg_tree); - else - return fold_build1_loc(location.gcc_location(), IMAGPART_EXPR, - TREE_TYPE(TREE_TYPE(arg_tree)), - arg_tree); - } - - case BUILTIN_COMPLEX: - { - const Expression_list* args = this->args(); - go_assert(args != NULL && args->size() == 2); - tree r = args->front()->get_tree(context); - tree i = args->back()->get_tree(context); - if (r == error_mark_node || i == error_mark_node) - return error_mark_node; - go_assert(TYPE_MAIN_VARIANT(TREE_TYPE(r)) - == TYPE_MAIN_VARIANT(TREE_TYPE(i))); - go_assert(SCALAR_FLOAT_TYPE_P(TREE_TYPE(r))); - return fold_build2_loc(location.gcc_location(), COMPLEX_EXPR, - build_complex_type(TREE_TYPE(r)), - r, i); - } - - default: - go_unreachable(); - } -} - -// We have to support exporting a builtin call expression, because -// code can set a constant to the result of a builtin expression. - -void -Builtin_call_expression::do_export(Export* exp) const -{ - Numeric_constant nc; - if (!this->numeric_constant_value(&nc)) - { - error_at(this->location(), "value is not constant"); - return; - } - - if (nc.is_int()) - { - mpz_t val; - nc.get_int(&val); - Integer_expression::export_integer(exp, val); - mpz_clear(val); - } - else if (nc.is_float()) - { - mpfr_t fval; - nc.get_float(&fval); - Float_expression::export_float(exp, fval); - mpfr_clear(fval); - } - else if (nc.is_complex()) - { - mpfr_t real; - mpfr_t imag; - Complex_expression::export_complex(exp, real, imag); - mpfr_clear(real); - mpfr_clear(imag); - } - else - go_unreachable(); - - // A trailing space lets us reliably identify the end of the number. - exp->write_c_string(" "); -} - -// Class Call_expression. - -// Traversal. - -int -Call_expression::do_traverse(Traverse* traverse) -{ - if (Expression::traverse(&this->fn_, traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - if (this->args_ != NULL) - { - if (this->args_->traverse(traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - return TRAVERSE_CONTINUE; -} - -// Lower a call statement. - -Expression* -Call_expression::do_lower(Gogo* gogo, Named_object* function, - Statement_inserter* inserter, int) -{ - Location loc = this->location(); - - // A type cast can look like a function call. - if (this->fn_->is_type_expression() - && this->args_ != NULL - && this->args_->size() == 1) - return Expression::make_cast(this->fn_->type(), this->args_->front(), - loc); - - // Because do_type will return an error type and thus prevent future - // errors, check for that case now to ensure that the error gets - // reported. - if (this->get_function_type() == NULL) - { - if (!this->fn_->type()->is_error()) - this->report_error(_("expected function")); - return Expression::make_error(loc); - } - - // Recognize a call to a builtin function. - Func_expression* fne = this->fn_->func_expression(); - if (fne != NULL - && fne->named_object()->is_function_declaration() - && fne->named_object()->func_declaration_value()->type()->is_builtin()) - return new Builtin_call_expression(gogo, this->fn_, this->args_, - this->is_varargs_, loc); - - // Handle an argument which is a call to a function which returns - // multiple results. - if (this->args_ != NULL - && this->args_->size() == 1 - && this->args_->front()->call_expression() != NULL - && this->fn_->type()->function_type() != NULL) - { - Function_type* fntype = this->fn_->type()->function_type(); - size_t rc = this->args_->front()->call_expression()->result_count(); - if (rc > 1 - && fntype->parameters() != NULL - && (fntype->parameters()->size() == rc - || (fntype->is_varargs() - && fntype->parameters()->size() - 1 <= rc))) - { - Call_expression* call = this->args_->front()->call_expression(); - Expression_list* args = new Expression_list; - for (size_t i = 0; i < rc; ++i) - args->push_back(Expression::make_call_result(call, i)); - // We can't return a new call expression here, because this - // one may be referenced by Call_result expressions. We - // also can't delete the old arguments, because we may still - // traverse them somewhere up the call stack. FIXME. - this->args_ = args; - } - } - - // If this call returns multiple results, create a temporary - // variable for each result. - size_t rc = this->result_count(); - if (rc > 1 && this->results_ == NULL) - { - std::vector<Temporary_statement*>* temps = - new std::vector<Temporary_statement*>; - temps->reserve(rc); - const Typed_identifier_list* results = - this->fn_->type()->function_type()->results(); - for (Typed_identifier_list::const_iterator p = results->begin(); - p != results->end(); - ++p) - { - Temporary_statement* temp = Statement::make_temporary(p->type(), - NULL, loc); - inserter->insert(temp); - temps->push_back(temp); - } - this->results_ = temps; - } - - // Handle a call to a varargs function by packaging up the extra - // parameters. - if (this->fn_->type()->function_type() != NULL - && this->fn_->type()->function_type()->is_varargs()) - { - Function_type* fntype = this->fn_->type()->function_type(); - const Typed_identifier_list* parameters = fntype->parameters(); - go_assert(parameters != NULL && !parameters->empty()); - Type* varargs_type = parameters->back().type(); - this->lower_varargs(gogo, function, inserter, varargs_type, - parameters->size()); - } - - // If this is call to a method, call the method directly passing the - // object as the first parameter. - Bound_method_expression* bme = this->fn_->bound_method_expression(); - if (bme != NULL) - { - Named_object* method = bme->method(); - Expression* first_arg = bme->first_argument(); - - // We always pass a pointer when calling a method. - if (first_arg->type()->points_to() == NULL - && !first_arg->type()->is_error()) - { - first_arg = Expression::make_unary(OPERATOR_AND, first_arg, loc); - // We may need to create a temporary variable so that we can - // take the address. We can't do that here because it will - // mess up the order of evaluation. - Unary_expression* ue = static_cast<Unary_expression*>(first_arg); - ue->set_create_temp(); - } - - // If we are calling a method which was inherited from an - // embedded struct, and the method did not get a stub, then the - // first type may be wrong. - Type* fatype = bme->first_argument_type(); - if (fatype != NULL) - { - if (fatype->points_to() == NULL) - fatype = Type::make_pointer_type(fatype); - first_arg = Expression::make_unsafe_cast(fatype, first_arg, loc); - } - - Expression_list* new_args = new Expression_list(); - new_args->push_back(first_arg); - if (this->args_ != NULL) - { - for (Expression_list::const_iterator p = this->args_->begin(); - p != this->args_->end(); - ++p) - new_args->push_back(*p); - } - - // We have to change in place because this structure may be - // referenced by Call_result_expressions. We can't delete the - // old arguments, because we may be traversing them up in some - // caller. FIXME. - this->args_ = new_args; - this->fn_ = Expression::make_func_reference(method, NULL, - bme->location()); - } - - return this; -} - -// Lower a call to a varargs function. FUNCTION is the function in -// which the call occurs--it's not the function we are calling. -// VARARGS_TYPE is the type of the varargs parameter, a slice type. -// PARAM_COUNT is the number of parameters of the function we are -// calling; the last of these parameters will be the varargs -// parameter. - -void -Call_expression::lower_varargs(Gogo* gogo, Named_object* function, - Statement_inserter* inserter, - Type* varargs_type, size_t param_count) -{ - if (this->varargs_are_lowered_) - return; - - Location loc = this->location(); - - go_assert(param_count > 0); - go_assert(varargs_type->is_slice_type()); - - size_t arg_count = this->args_ == NULL ? 0 : this->args_->size(); - if (arg_count < param_count - 1) - { - // Not enough arguments; will be caught in check_types. - return; - } - - Expression_list* old_args = this->args_; - Expression_list* new_args = new Expression_list(); - bool push_empty_arg = false; - if (old_args == NULL || old_args->empty()) - { - go_assert(param_count == 1); - push_empty_arg = true; - } - else - { - Expression_list::const_iterator pa; - int i = 1; - for (pa = old_args->begin(); pa != old_args->end(); ++pa, ++i) - { - if (static_cast<size_t>(i) == param_count) - break; - new_args->push_back(*pa); - } - - // We have reached the varargs parameter. - - bool issued_error = false; - if (pa == old_args->end()) - push_empty_arg = true; - else if (pa + 1 == old_args->end() && this->is_varargs_) - new_args->push_back(*pa); - else if (this->is_varargs_) - { - if ((*pa)->type()->is_slice_type()) - this->report_error(_("too many arguments")); - else - { - error_at(this->location(), - _("invalid use of %<...%> with non-slice")); - this->set_is_error(); - } - return; - } - else - { - Type* element_type = varargs_type->array_type()->element_type(); - Expression_list* vals = new Expression_list; - for (; pa != old_args->end(); ++pa, ++i) - { - // Check types here so that we get a better message. - Type* patype = (*pa)->type(); - Location paloc = (*pa)->location(); - if (!this->check_argument_type(i, element_type, patype, - paloc, issued_error)) - continue; - vals->push_back(*pa); - } - Expression* val = - Expression::make_slice_composite_literal(varargs_type, vals, loc); - gogo->lower_expression(function, inserter, &val); - new_args->push_back(val); - } - } - - if (push_empty_arg) - new_args->push_back(Expression::make_nil(loc)); - - // We can't return a new call expression here, because this one may - // be referenced by Call_result expressions. FIXME. We can't - // delete OLD_ARGS because we may have both a Call_expression and a - // Builtin_call_expression which refer to them. FIXME. - this->args_ = new_args; - this->varargs_are_lowered_ = true; -} - -// Get the function type. This can return NULL in error cases. - -Function_type* -Call_expression::get_function_type() const -{ - return this->fn_->type()->function_type(); -} - -// Return the number of values which this call will return. - -size_t -Call_expression::result_count() const -{ - const Function_type* fntype = this->get_function_type(); - if (fntype == NULL) - return 0; - if (fntype->results() == NULL) - return 0; - return fntype->results()->size(); -} - -// Return the temporary which holds a result. - -Temporary_statement* -Call_expression::result(size_t i) const -{ - if (this->results_ == NULL || this->results_->size() <= i) - { - go_assert(saw_errors()); - return NULL; - } - return (*this->results_)[i]; -} - -// Return whether this is a call to the predeclared function recover. - -bool -Call_expression::is_recover_call() const -{ - return this->do_is_recover_call(); -} - -// Set the argument to the recover function. - -void -Call_expression::set_recover_arg(Expression* arg) -{ - this->do_set_recover_arg(arg); -} - -// Virtual functions also implemented by Builtin_call_expression. - -bool -Call_expression::do_is_recover_call() const -{ - return false; -} - -void -Call_expression::do_set_recover_arg(Expression*) -{ - go_unreachable(); -} - -// We have found an error with this call expression; return true if -// we should report it. - -bool -Call_expression::issue_error() -{ - if (this->issued_error_) - return false; - else - { - this->issued_error_ = true; - return true; - } -} - -// Get the type. - -Type* -Call_expression::do_type() -{ - if (this->type_ != NULL) - return this->type_; - - Type* ret; - Function_type* fntype = this->get_function_type(); - if (fntype == NULL) - return Type::make_error_type(); - - const Typed_identifier_list* results = fntype->results(); - if (results == NULL) - ret = Type::make_void_type(); - else if (results->size() == 1) - ret = results->begin()->type(); - else - ret = Type::make_call_multiple_result_type(this); - - this->type_ = ret; - - return this->type_; -} - -// Determine types for a call expression. We can use the function -// parameter types to set the types of the arguments. - -void -Call_expression::do_determine_type(const Type_context*) -{ - if (!this->determining_types()) - return; - - this->fn_->determine_type_no_context(); - Function_type* fntype = this->get_function_type(); - const Typed_identifier_list* parameters = NULL; - if (fntype != NULL) - parameters = fntype->parameters(); - if (this->args_ != NULL) - { - Typed_identifier_list::const_iterator pt; - if (parameters != NULL) - pt = parameters->begin(); - bool first = true; - for (Expression_list::const_iterator pa = this->args_->begin(); - pa != this->args_->end(); - ++pa) - { - if (first) - { - first = false; - // If this is a method, the first argument is the - // receiver. - if (fntype != NULL && fntype->is_method()) - { - Type* rtype = fntype->receiver()->type(); - // The receiver is always passed as a pointer. - if (rtype->points_to() == NULL) - rtype = Type::make_pointer_type(rtype); - Type_context subcontext(rtype, false); - (*pa)->determine_type(&subcontext); - continue; - } - } - - if (parameters != NULL && pt != parameters->end()) - { - Type_context subcontext(pt->type(), false); - (*pa)->determine_type(&subcontext); - ++pt; - } - else - (*pa)->determine_type_no_context(); - } - } -} - -// Called when determining types for a Call_expression. Return true -// if we should go ahead, false if they have already been determined. - -bool -Call_expression::determining_types() -{ - if (this->types_are_determined_) - return false; - else - { - this->types_are_determined_ = true; - return true; - } -} - -// Check types for parameter I. - -bool -Call_expression::check_argument_type(int i, const Type* parameter_type, - const Type* argument_type, - Location argument_location, - bool issued_error) -{ - std::string reason; - bool ok; - if (this->are_hidden_fields_ok_) - ok = Type::are_assignable_hidden_ok(parameter_type, argument_type, - &reason); - else - ok = Type::are_assignable(parameter_type, argument_type, &reason); - if (!ok) - { - if (!issued_error) - { - if (reason.empty()) - error_at(argument_location, "argument %d has incompatible type", i); - else - error_at(argument_location, - "argument %d has incompatible type (%s)", - i, reason.c_str()); - } - this->set_is_error(); - return false; - } - return true; -} - -// Check types. - -void -Call_expression::do_check_types(Gogo*) -{ - if (this->classification() == EXPRESSION_ERROR) - return; - - Function_type* fntype = this->get_function_type(); - if (fntype == NULL) - { - if (!this->fn_->type()->is_error()) - this->report_error(_("expected function")); - return; - } - - bool is_method = fntype->is_method(); - if (is_method) - { - go_assert(this->args_ != NULL && !this->args_->empty()); - Type* rtype = fntype->receiver()->type(); - Expression* first_arg = this->args_->front(); - // The language permits copying hidden fields for a method - // receiver. We dereference the values since receivers are - // always passed as pointers. - std::string reason; - if (!Type::are_assignable_hidden_ok(rtype->deref(), - first_arg->type()->deref(), - &reason)) - { - if (reason.empty()) - this->report_error(_("incompatible type for receiver")); - else - { - error_at(this->location(), - "incompatible type for receiver (%s)", - reason.c_str()); - this->set_is_error(); - } - } - } - - // Note that varargs was handled by the lower_varargs() method, so - // we don't have to worry about it here unless something is wrong. - if (this->is_varargs_ && !this->varargs_are_lowered_) - { - if (!fntype->is_varargs()) - { - error_at(this->location(), - _("invalid use of %<...%> calling non-variadic function")); - this->set_is_error(); - return; - } - } - - const Typed_identifier_list* parameters = fntype->parameters(); - if (this->args_ == NULL) - { - if (parameters != NULL && !parameters->empty()) - this->report_error(_("not enough arguments")); - } - else if (parameters == NULL) - { - if (!is_method || this->args_->size() > 1) - this->report_error(_("too many arguments")); - } - else - { - int i = 0; - Expression_list::const_iterator pa = this->args_->begin(); - if (is_method) - ++pa; - for (Typed_identifier_list::const_iterator pt = parameters->begin(); - pt != parameters->end(); - ++pt, ++pa, ++i) - { - if (pa == this->args_->end()) - { - this->report_error(_("not enough arguments")); - return; - } - this->check_argument_type(i + 1, pt->type(), (*pa)->type(), - (*pa)->location(), false); - } - if (pa != this->args_->end()) - this->report_error(_("too many arguments")); - } -} - -// Return whether we have to use a temporary variable to ensure that -// we evaluate this call expression in order. If the call returns no -// results then it will inevitably be executed last. - -bool -Call_expression::do_must_eval_in_order() const -{ - return this->result_count() > 0; -} - -// Get the function and the first argument to use when calling an -// interface method. - -tree -Call_expression::interface_method_function( - Translate_context* context, - Interface_field_reference_expression* interface_method, - tree* first_arg_ptr) -{ - tree expr = interface_method->expr()->get_tree(context); - if (expr == error_mark_node) - return error_mark_node; - expr = save_expr(expr); - tree first_arg = interface_method->get_underlying_object_tree(context, expr); - if (first_arg == error_mark_node) - return error_mark_node; - *first_arg_ptr = first_arg; - return interface_method->get_function_tree(context, expr); -} - -// Build the call expression. - -tree -Call_expression::do_get_tree(Translate_context* context) -{ - if (this->tree_ != NULL_TREE) - return this->tree_; - - Function_type* fntype = this->get_function_type(); - if (fntype == NULL) - return error_mark_node; - - if (this->fn_->is_error_expression()) - return error_mark_node; - - Gogo* gogo = context->gogo(); - Location location = this->location(); - - Func_expression* func = this->fn_->func_expression(); - Interface_field_reference_expression* interface_method = - this->fn_->interface_field_reference_expression(); - const bool has_closure = func != NULL && func->closure() != NULL; - const bool is_interface_method = interface_method != NULL; - - int nargs; - tree* args; - if (this->args_ == NULL || this->args_->empty()) - { - nargs = is_interface_method ? 1 : 0; - args = nargs == 0 ? NULL : new tree[nargs]; - } - else if (fntype->parameters() == NULL || fntype->parameters()->empty()) - { - // Passing a receiver parameter. - go_assert(!is_interface_method - && fntype->is_method() - && this->args_->size() == 1); - nargs = 1; - args = new tree[nargs]; - args[0] = this->args_->front()->get_tree(context); - } - else - { - const Typed_identifier_list* params = fntype->parameters(); - - nargs = this->args_->size(); - int i = is_interface_method ? 1 : 0; - nargs += i; - args = new tree[nargs]; - - Typed_identifier_list::const_iterator pp = params->begin(); - Expression_list::const_iterator pe = this->args_->begin(); - if (!is_interface_method && fntype->is_method()) - { - args[i] = (*pe)->get_tree(context); - ++pe; - ++i; - } - for (; pe != this->args_->end(); ++pe, ++pp, ++i) - { - go_assert(pp != params->end()); - tree arg_val = (*pe)->get_tree(context); - args[i] = Expression::convert_for_assignment(context, - pp->type(), - (*pe)->type(), - arg_val, - location); - if (args[i] == error_mark_node) - { - delete[] args; - return error_mark_node; - } - } - go_assert(pp == params->end()); - go_assert(i == nargs); - } - - tree rettype = TREE_TYPE(TREE_TYPE(type_to_tree(fntype->get_backend(gogo)))); - if (rettype == error_mark_node) - { - delete[] args; - return error_mark_node; - } - - tree fn; - if (has_closure) - fn = func->get_tree_without_closure(gogo); - else if (!is_interface_method) - fn = this->fn_->get_tree(context); - else - fn = this->interface_method_function(context, interface_method, &args[0]); - - if (fn == error_mark_node || TREE_TYPE(fn) == error_mark_node) - { - delete[] args; - return error_mark_node; - } - - tree fndecl = fn; - if (TREE_CODE(fndecl) == ADDR_EXPR) - fndecl = TREE_OPERAND(fndecl, 0); - - // Add a type cast in case the type of the function is a recursive - // type which refers to itself. - if (!DECL_P(fndecl) || !DECL_IS_BUILTIN(fndecl)) - { - tree fnt = type_to_tree(fntype->get_backend(gogo)); - if (fnt == error_mark_node) - return error_mark_node; - fn = fold_convert_loc(location.gcc_location(), fnt, fn); - } - - // This is to support builtin math functions when using 80387 math. - tree excess_type = NULL_TREE; - if (optimize - && TREE_CODE(fndecl) == FUNCTION_DECL - && DECL_IS_BUILTIN(fndecl) - && DECL_BUILT_IN_CLASS(fndecl) == BUILT_IN_NORMAL - && nargs > 0 - && ((SCALAR_FLOAT_TYPE_P(rettype) - && SCALAR_FLOAT_TYPE_P(TREE_TYPE(args[0]))) - || (COMPLEX_FLOAT_TYPE_P(rettype) - && COMPLEX_FLOAT_TYPE_P(TREE_TYPE(args[0]))))) - { - excess_type = excess_precision_type(TREE_TYPE(args[0])); - if (excess_type != NULL_TREE) - { - tree excess_fndecl = mathfn_built_in(excess_type, - DECL_FUNCTION_CODE(fndecl)); - if (excess_fndecl == NULL_TREE) - excess_type = NULL_TREE; - else - { - fn = build_fold_addr_expr_loc(location.gcc_location(), - excess_fndecl); - for (int i = 0; i < nargs; ++i) - { - if (SCALAR_FLOAT_TYPE_P(TREE_TYPE(args[i])) - || COMPLEX_FLOAT_TYPE_P(TREE_TYPE(args[i]))) - args[i] = ::convert(excess_type, args[i]); - } - } - } - } - - if (func == NULL) - fn = save_expr(fn); - - tree ret = build_call_array(excess_type != NULL_TREE ? excess_type : rettype, - fn, nargs, args); - delete[] args; - - SET_EXPR_LOCATION(ret, location.gcc_location()); - - if (has_closure) - { - tree closure_tree = func->closure()->get_tree(context); - if (closure_tree != error_mark_node) - CALL_EXPR_STATIC_CHAIN(ret) = closure_tree; - } - - // If this is a recursive function type which returns itself, as in - // type F func() F - // we have used ptr_type_node for the return type. Add a cast here - // to the correct type. - if (TREE_TYPE(ret) == ptr_type_node) - { - tree t = type_to_tree(this->type()->base()->get_backend(gogo)); - ret = fold_convert_loc(location.gcc_location(), t, ret); - } - - if (excess_type != NULL_TREE) - { - // Calling convert here can undo our excess precision change. - // That may or may not be a bug in convert_to_real. - ret = build1(NOP_EXPR, rettype, ret); - } - - if (this->results_ != NULL) - ret = this->set_results(context, ret); - - // We can't unwind the stack past a call to nil, so we need to - // insert an explicit check so that the panic can be recovered. - if (func == NULL) - { - tree compare = fold_build2_loc(location.gcc_location(), EQ_EXPR, - boolean_type_node, fn, - fold_convert_loc(location.gcc_location(), - TREE_TYPE(fn), - null_pointer_node)); - tree crash = build3_loc(location.gcc_location(), COND_EXPR, - void_type_node, compare, - gogo->runtime_error(RUNTIME_ERROR_NIL_DEREFERENCE, - location), - NULL_TREE); - ret = fold_build2_loc(location.gcc_location(), COMPOUND_EXPR, - TREE_TYPE(ret), crash, ret); - } - - this->tree_ = ret; - - return ret; -} - -// Set the result variables if this call returns multiple results. - -tree -Call_expression::set_results(Translate_context* context, tree call_tree) -{ - tree stmt_list = NULL_TREE; - - call_tree = save_expr(call_tree); - - if (TREE_CODE(TREE_TYPE(call_tree)) != RECORD_TYPE) - { - go_assert(saw_errors()); - return call_tree; - } - - Location loc = this->location(); - tree field = TYPE_FIELDS(TREE_TYPE(call_tree)); - size_t rc = this->result_count(); - for (size_t i = 0; i < rc; ++i, field = DECL_CHAIN(field)) - { - go_assert(field != NULL_TREE); - - Temporary_statement* temp = this->result(i); - if (temp == NULL) - { - go_assert(saw_errors()); - return error_mark_node; - } - Temporary_reference_expression* ref = - Expression::make_temporary_reference(temp, loc); - ref->set_is_lvalue(); - tree temp_tree = ref->get_tree(context); - if (temp_tree == error_mark_node) - return error_mark_node; - - tree val_tree = build3_loc(loc.gcc_location(), COMPONENT_REF, - TREE_TYPE(field), call_tree, field, NULL_TREE); - tree set_tree = build2_loc(loc.gcc_location(), MODIFY_EXPR, - void_type_node, temp_tree, val_tree); - - append_to_statement_list(set_tree, &stmt_list); - } - go_assert(field == NULL_TREE); - - return save_expr(stmt_list); -} - -// Dump ast representation for a call expressin. - -void -Call_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const -{ - this->fn_->dump_expression(ast_dump_context); - ast_dump_context->ostream() << "("; - if (args_ != NULL) - ast_dump_context->dump_expression_list(this->args_); - - ast_dump_context->ostream() << ") "; -} - -// Make a call expression. - -Call_expression* -Expression::make_call(Expression* fn, Expression_list* args, bool is_varargs, - Location location) -{ - return new Call_expression(fn, args, is_varargs, location); -} - -// A single result from a call which returns multiple results. - -class Call_result_expression : public Expression -{ - public: - Call_result_expression(Call_expression* call, unsigned int index) - : Expression(EXPRESSION_CALL_RESULT, call->location()), - call_(call), index_(index) - { } - - protected: - int - do_traverse(Traverse*); - - Type* - do_type(); - - void - do_determine_type(const Type_context*); - - void - do_check_types(Gogo*); - - Expression* - do_copy() - { - return new Call_result_expression(this->call_->call_expression(), - this->index_); - } - - bool - do_must_eval_in_order() const - { return true; } - - tree - do_get_tree(Translate_context*); - - void - do_dump_expression(Ast_dump_context*) const; - - private: - // The underlying call expression. - Expression* call_; - // Which result we want. - unsigned int index_; -}; - -// Traverse a call result. - -int -Call_result_expression::do_traverse(Traverse* traverse) -{ - if (traverse->remember_expression(this->call_)) - { - // We have already traversed the call expression. - return TRAVERSE_CONTINUE; - } - return Expression::traverse(&this->call_, traverse); -} - -// Get the type. - -Type* -Call_result_expression::do_type() -{ - if (this->classification() == EXPRESSION_ERROR) - return Type::make_error_type(); - - // THIS->CALL_ can be replaced with a temporary reference due to - // Call_expression::do_must_eval_in_order when there is an error. - Call_expression* ce = this->call_->call_expression(); - if (ce == NULL) - { - this->set_is_error(); - return Type::make_error_type(); - } - Function_type* fntype = ce->get_function_type(); - if (fntype == NULL) - { - if (ce->issue_error()) - { - if (!ce->fn()->type()->is_error()) - this->report_error(_("expected function")); - } - this->set_is_error(); - return Type::make_error_type(); - } - const Typed_identifier_list* results = fntype->results(); - if (results == NULL || results->size() < 2) - { - if (ce->issue_error()) - this->report_error(_("number of results does not match " - "number of values")); - return Type::make_error_type(); - } - Typed_identifier_list::const_iterator pr = results->begin(); - for (unsigned int i = 0; i < this->index_; ++i) - { - if (pr == results->end()) - break; - ++pr; - } - if (pr == results->end()) - { - if (ce->issue_error()) - this->report_error(_("number of results does not match " - "number of values")); - return Type::make_error_type(); - } - return pr->type(); -} - -// Check the type. Just make sure that we trigger the warning in -// do_type. - -void -Call_result_expression::do_check_types(Gogo*) -{ - this->type(); -} - -// Determine the type. We have nothing to do here, but the 0 result -// needs to pass down to the caller. - -void -Call_result_expression::do_determine_type(const Type_context*) -{ - this->call_->determine_type_no_context(); -} - -// Return the tree. We just refer to the temporary set by the call -// expression. We don't do this at lowering time because it makes it -// hard to evaluate the call at the right time. - -tree -Call_result_expression::do_get_tree(Translate_context* context) -{ - Call_expression* ce = this->call_->call_expression(); - if (ce == NULL) - { - go_assert(this->call_->is_error_expression()); - return error_mark_node; - } - Temporary_statement* ts = ce->result(this->index_); - if (ts == NULL) - { - go_assert(saw_errors()); - return error_mark_node; - } - Expression* ref = Expression::make_temporary_reference(ts, this->location()); - return ref->get_tree(context); -} - -// Dump ast representation for a call result expression. - -void -Call_result_expression::do_dump_expression(Ast_dump_context* ast_dump_context) - const -{ - // FIXME: Wouldn't it be better if the call is assigned to a temporary - // (struct) and the fields are referenced instead. - ast_dump_context->ostream() << this->index_ << "@("; - ast_dump_context->dump_expression(this->call_); - ast_dump_context->ostream() << ")"; -} - -// Make a reference to a single result of a call which returns -// multiple results. - -Expression* -Expression::make_call_result(Call_expression* call, unsigned int index) -{ - return new Call_result_expression(call, index); -} - -// Class Index_expression. - -// Traversal. - -int -Index_expression::do_traverse(Traverse* traverse) -{ - if (Expression::traverse(&this->left_, traverse) == TRAVERSE_EXIT - || Expression::traverse(&this->start_, traverse) == TRAVERSE_EXIT - || (this->end_ != NULL - && Expression::traverse(&this->end_, traverse) == TRAVERSE_EXIT)) - return TRAVERSE_EXIT; - return TRAVERSE_CONTINUE; -} - -// Lower an index expression. This converts the generic index -// expression into an array index, a string index, or a map index. - -Expression* -Index_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int) -{ - Location location = this->location(); - Expression* left = this->left_; - Expression* start = this->start_; - Expression* end = this->end_; - - Type* type = left->type(); - if (type->is_error()) - return Expression::make_error(location); - else if (left->is_type_expression()) - { - error_at(location, "attempt to index type expression"); - return Expression::make_error(location); - } - else if (type->array_type() != NULL) - return Expression::make_array_index(left, start, end, location); - else if (type->points_to() != NULL - && type->points_to()->array_type() != NULL - && !type->points_to()->is_slice_type()) - { - Expression* deref = Expression::make_unary(OPERATOR_MULT, left, - location); - return Expression::make_array_index(deref, start, end, location); - } - else if (type->is_string_type()) - return Expression::make_string_index(left, start, end, location); - else if (type->map_type() != NULL) - { - if (end != NULL) - { - error_at(location, "invalid slice of map"); - return Expression::make_error(location); - } - Map_index_expression* ret = Expression::make_map_index(left, start, - location); - if (this->is_lvalue_) - ret->set_is_lvalue(); - return ret; - } - else - { - error_at(location, - "attempt to index object which is not array, string, or map"); - return Expression::make_error(location); - } -} - -// Write an indexed expression (expr[expr:expr] or expr[expr]) to a -// dump context - -void -Index_expression::dump_index_expression(Ast_dump_context* ast_dump_context, - const Expression* expr, - const Expression* start, - const Expression* end) -{ - expr->dump_expression(ast_dump_context); - ast_dump_context->ostream() << "["; - start->dump_expression(ast_dump_context); - if (end != NULL) - { - ast_dump_context->ostream() << ":"; - end->dump_expression(ast_dump_context); - } - ast_dump_context->ostream() << "]"; -} - -// Dump ast representation for an index expression. - -void -Index_expression::do_dump_expression(Ast_dump_context* ast_dump_context) - const -{ - Index_expression::dump_index_expression(ast_dump_context, this->left_, - this->start_, this->end_); -} - -// Make an index expression. - -Expression* -Expression::make_index(Expression* left, Expression* start, Expression* end, - Location location) -{ - return new Index_expression(left, start, end, location); -} - -// An array index. This is used for both indexing and slicing. - -class Array_index_expression : public Expression -{ - public: - Array_index_expression(Expression* array, Expression* start, - Expression* end, Location location) - : Expression(EXPRESSION_ARRAY_INDEX, location), - array_(array), start_(start), end_(end), type_(NULL) - { } - - protected: - int - do_traverse(Traverse*); - - Type* - do_type(); - - void - do_determine_type(const Type_context*); - - void - do_check_types(Gogo*); - - Expression* - do_copy() - { - return Expression::make_array_index(this->array_->copy(), - this->start_->copy(), - (this->end_ == NULL - ? NULL - : this->end_->copy()), - this->location()); - } - - bool - do_must_eval_subexpressions_in_order(int* skip) const - { - *skip = 1; - return true; - } - - bool - do_is_addressable() const; - - void - do_address_taken(bool escapes) - { this->array_->address_taken(escapes); } - - tree - do_get_tree(Translate_context*); - - void - do_dump_expression(Ast_dump_context*) const; - - private: - // The array we are getting a value from. - Expression* array_; - // The start or only index. - Expression* start_; - // The end index of a slice. This may be NULL for a simple array - // index, or it may be a nil expression for the length of the array. - Expression* end_; - // The type of the expression. - Type* type_; -}; - -// Array index traversal. - -int -Array_index_expression::do_traverse(Traverse* traverse) -{ - if (Expression::traverse(&this->array_, traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - if (Expression::traverse(&this->start_, traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - if (this->end_ != NULL) - { - if (Expression::traverse(&this->end_, traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - return TRAVERSE_CONTINUE; -} - -// Return the type of an array index. - -Type* -Array_index_expression::do_type() -{ - if (this->type_ == NULL) - { - Array_type* type = this->array_->type()->array_type(); - if (type == NULL) - this->type_ = Type::make_error_type(); - else if (this->end_ == NULL) - this->type_ = type->element_type(); - else if (type->is_slice_type()) - { - // A slice of a slice has the same type as the original - // slice. - this->type_ = this->array_->type()->deref(); - } - else - { - // A slice of an array is a slice. - this->type_ = Type::make_array_type(type->element_type(), NULL); - } - } - return this->type_; -} - -// Set the type of an array index. - -void -Array_index_expression::do_determine_type(const Type_context*) -{ - this->array_->determine_type_no_context(); - this->start_->determine_type_no_context(); - if (this->end_ != NULL) - this->end_->determine_type_no_context(); -} - -// Check types of an array index. - -void -Array_index_expression::do_check_types(Gogo*) -{ - if (this->start_->type()->integer_type() == NULL) - this->report_error(_("index must be integer")); - if (this->end_ != NULL - && this->end_->type()->integer_type() == NULL - && !this->end_->type()->is_error() - && !this->end_->is_nil_expression() - && !this->end_->is_error_expression()) - this->report_error(_("slice end must be integer")); - - Array_type* array_type = this->array_->type()->array_type(); - if (array_type == NULL) - { - go_assert(this->array_->type()->is_error()); - return; - } - - unsigned int int_bits = - Type::lookup_integer_type("int")->integer_type()->bits(); - - Numeric_constant lvalnc; - mpz_t lval; - bool lval_valid = (array_type->length() != NULL - && array_type->length()->numeric_constant_value(&lvalnc) - && lvalnc.to_int(&lval)); - Numeric_constant inc; - mpz_t ival; - bool ival_valid = false; - if (this->start_->numeric_constant_value(&inc) && inc.to_int(&ival)) - { - ival_valid = true; - if (mpz_sgn(ival) < 0 - || mpz_sizeinbase(ival, 2) >= int_bits - || (lval_valid - && (this->end_ == NULL - ? mpz_cmp(ival, lval) >= 0 - : mpz_cmp(ival, lval) > 0))) - { - error_at(this->start_->location(), "array index out of bounds"); - this->set_is_error(); - } - } - if (this->end_ != NULL && !this->end_->is_nil_expression()) - { - Numeric_constant enc; - mpz_t eval; - if (this->end_->numeric_constant_value(&enc) && enc.to_int(&eval)) - { - if (mpz_sgn(eval) < 0 - || mpz_sizeinbase(eval, 2) >= int_bits - || (lval_valid && mpz_cmp(eval, lval) > 0)) - { - error_at(this->end_->location(), "array index out of bounds"); - this->set_is_error(); - } - else if (ival_valid && mpz_cmp(ival, eval) > 0) - this->report_error(_("inverted slice range")); - mpz_clear(eval); - } - } - if (ival_valid) - mpz_clear(ival); - if (lval_valid) - mpz_clear(lval); - - // A slice of an array requires an addressable array. A slice of a - // slice is always possible. - if (this->end_ != NULL && !array_type->is_slice_type()) - { - if (!this->array_->is_addressable()) - this->report_error(_("slice of unaddressable value")); - else - this->array_->address_taken(true); - } -} - -// Return whether this expression is addressable. - -bool -Array_index_expression::do_is_addressable() const -{ - // A slice expression is not addressable. - if (this->end_ != NULL) - return false; - - // An index into a slice is addressable. - if (this->array_->type()->is_slice_type()) - return true; - - // An index into an array is addressable if the array is - // addressable. - return this->array_->is_addressable(); -} - -// Get a tree for an array index. - -tree -Array_index_expression::do_get_tree(Translate_context* context) -{ - Gogo* gogo = context->gogo(); - Location loc = this->location(); - - Array_type* array_type = this->array_->type()->array_type(); - if (array_type == NULL) - { - go_assert(this->array_->type()->is_error()); - return error_mark_node; - } - - tree type_tree = type_to_tree(array_type->get_backend(gogo)); - if (type_tree == error_mark_node) - return error_mark_node; - - tree array_tree = this->array_->get_tree(context); - if (array_tree == error_mark_node) - return error_mark_node; - - if (array_type->length() == NULL && !DECL_P(array_tree)) - array_tree = save_expr(array_tree); - - tree length_tree = NULL_TREE; - if (this->end_ == NULL || this->end_->is_nil_expression()) - { - length_tree = array_type->length_tree(gogo, array_tree); - if (length_tree == error_mark_node) - return error_mark_node; - length_tree = save_expr(length_tree); - } - - tree capacity_tree = NULL_TREE; - if (this->end_ != NULL) - { - capacity_tree = array_type->capacity_tree(gogo, array_tree); - if (capacity_tree == error_mark_node) - return error_mark_node; - capacity_tree = save_expr(capacity_tree); - } - - tree length_type = (length_tree != NULL_TREE - ? TREE_TYPE(length_tree) - : TREE_TYPE(capacity_tree)); - - tree bad_index = boolean_false_node; - - tree start_tree = this->start_->get_tree(context); - if (start_tree == error_mark_node) - return error_mark_node; - if (!DECL_P(start_tree)) - start_tree = save_expr(start_tree); - if (!INTEGRAL_TYPE_P(TREE_TYPE(start_tree))) - start_tree = convert_to_integer(length_type, start_tree); - - bad_index = Expression::check_bounds(start_tree, length_type, bad_index, - loc); - - start_tree = fold_convert_loc(loc.gcc_location(), length_type, start_tree); - bad_index = fold_build2_loc(loc.gcc_location(), TRUTH_OR_EXPR, - boolean_type_node, bad_index, - fold_build2_loc(loc.gcc_location(), - (this->end_ == NULL - ? GE_EXPR - : GT_EXPR), - boolean_type_node, start_tree, - (this->end_ == NULL - ? length_tree - : capacity_tree))); - - int code = (array_type->length() != NULL - ? (this->end_ == NULL - ? RUNTIME_ERROR_ARRAY_INDEX_OUT_OF_BOUNDS - : RUNTIME_ERROR_ARRAY_SLICE_OUT_OF_BOUNDS) - : (this->end_ == NULL - ? RUNTIME_ERROR_SLICE_INDEX_OUT_OF_BOUNDS - : RUNTIME_ERROR_SLICE_SLICE_OUT_OF_BOUNDS)); - tree crash = gogo->runtime_error(code, loc); - - if (this->end_ == NULL) - { - // Simple array indexing. This has to return an l-value, so - // wrap the index check into START_TREE. - start_tree = build2(COMPOUND_EXPR, TREE_TYPE(start_tree), - build3(COND_EXPR, void_type_node, - bad_index, crash, NULL_TREE), - start_tree); - start_tree = fold_convert_loc(loc.gcc_location(), sizetype, start_tree); - - if (array_type->length() != NULL) - { - // Fixed array. - return build4(ARRAY_REF, TREE_TYPE(type_tree), array_tree, - start_tree, NULL_TREE, NULL_TREE); - } - else - { - // Open array. - tree values = array_type->value_pointer_tree(gogo, array_tree); - Type* element_type = array_type->element_type(); - Btype* belement_type = element_type->get_backend(gogo); - tree element_type_tree = type_to_tree(belement_type); - if (element_type_tree == error_mark_node) - return error_mark_node; - tree element_size = TYPE_SIZE_UNIT(element_type_tree); - tree offset = fold_build2_loc(loc.gcc_location(), MULT_EXPR, sizetype, - start_tree, element_size); - tree ptr = fold_build2_loc(loc.gcc_location(), POINTER_PLUS_EXPR, - TREE_TYPE(values), values, offset); - return build_fold_indirect_ref(ptr); - } - } - - // Array slice. - - tree end_tree; - if (this->end_->is_nil_expression()) - end_tree = length_tree; - else - { - end_tree = this->end_->get_tree(context); - if (end_tree == error_mark_node) - return error_mark_node; - if (!DECL_P(end_tree)) - end_tree = save_expr(end_tree); - if (!INTEGRAL_TYPE_P(TREE_TYPE(end_tree))) - end_tree = convert_to_integer(length_type, end_tree); - - bad_index = Expression::check_bounds(end_tree, length_type, bad_index, - loc); - - end_tree = fold_convert_loc(loc.gcc_location(), length_type, end_tree); - - tree bad_end = fold_build2_loc(loc.gcc_location(), TRUTH_OR_EXPR, - boolean_type_node, - fold_build2_loc(loc.gcc_location(), - LT_EXPR, boolean_type_node, - end_tree, start_tree), - fold_build2_loc(loc.gcc_location(), - GT_EXPR, boolean_type_node, - end_tree, capacity_tree)); - bad_index = fold_build2_loc(loc.gcc_location(), TRUTH_OR_EXPR, - boolean_type_node, bad_index, bad_end); - } - - Type* element_type = array_type->element_type(); - tree element_type_tree = type_to_tree(element_type->get_backend(gogo)); - if (element_type_tree == error_mark_node) - return error_mark_node; - tree element_size = TYPE_SIZE_UNIT(element_type_tree); - - tree offset = fold_build2_loc(loc.gcc_location(), MULT_EXPR, sizetype, - fold_convert_loc(loc.gcc_location(), sizetype, - start_tree), - element_size); - - tree value_pointer = array_type->value_pointer_tree(gogo, array_tree); - if (value_pointer == error_mark_node) - return error_mark_node; - - value_pointer = fold_build2_loc(loc.gcc_location(), POINTER_PLUS_EXPR, - TREE_TYPE(value_pointer), - value_pointer, offset); - - tree result_length_tree = fold_build2_loc(loc.gcc_location(), MINUS_EXPR, - length_type, end_tree, start_tree); - - tree result_capacity_tree = fold_build2_loc(loc.gcc_location(), MINUS_EXPR, - length_type, capacity_tree, - start_tree); - - tree struct_tree = type_to_tree(this->type()->get_backend(gogo)); - go_assert(TREE_CODE(struct_tree) == RECORD_TYPE); - - vec<constructor_elt, va_gc> *init; - vec_alloc (init, 3); - - constructor_elt empty = {NULL, NULL}; - constructor_elt* elt = init->quick_push(empty); - tree field = TYPE_FIELDS(struct_tree); - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__values") == 0); - elt->index = field; - elt->value = value_pointer; - - elt = init->quick_push(empty); - field = DECL_CHAIN(field); - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__count") == 0); - elt->index = field; - elt->value = fold_convert_loc(loc.gcc_location(), TREE_TYPE(field), - result_length_tree); - - elt = init->quick_push(empty); - field = DECL_CHAIN(field); - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__capacity") == 0); - elt->index = field; - elt->value = fold_convert_loc(loc.gcc_location(), TREE_TYPE(field), - result_capacity_tree); - - tree constructor = build_constructor(struct_tree, init); - - if (TREE_CONSTANT(value_pointer) - && TREE_CONSTANT(result_length_tree) - && TREE_CONSTANT(result_capacity_tree)) - TREE_CONSTANT(constructor) = 1; - - return fold_build2_loc(loc.gcc_location(), COMPOUND_EXPR, - TREE_TYPE(constructor), - build3(COND_EXPR, void_type_node, - bad_index, crash, NULL_TREE), - constructor); -} - -// Dump ast representation for an array index expression. - -void -Array_index_expression::do_dump_expression(Ast_dump_context* ast_dump_context) - const -{ - Index_expression::dump_index_expression(ast_dump_context, this->array_, - this->start_, this->end_); -} - -// Make an array index expression. END may be NULL. - -Expression* -Expression::make_array_index(Expression* array, Expression* start, - Expression* end, Location location) -{ - return new Array_index_expression(array, start, end, location); -} - -// A string index. This is used for both indexing and slicing. - -class String_index_expression : public Expression -{ - public: - String_index_expression(Expression* string, Expression* start, - Expression* end, Location location) - : Expression(EXPRESSION_STRING_INDEX, location), - string_(string), start_(start), end_(end) - { } - - protected: - int - do_traverse(Traverse*); - - Type* - do_type(); - - void - do_determine_type(const Type_context*); - - void - do_check_types(Gogo*); - - Expression* - do_copy() - { - return Expression::make_string_index(this->string_->copy(), - this->start_->copy(), - (this->end_ == NULL - ? NULL - : this->end_->copy()), - this->location()); - } - - bool - do_must_eval_subexpressions_in_order(int* skip) const - { - *skip = 1; - return true; - } - - tree - do_get_tree(Translate_context*); - - void - do_dump_expression(Ast_dump_context*) const; - - private: - // The string we are getting a value from. - Expression* string_; - // The start or only index. - Expression* start_; - // The end index of a slice. This may be NULL for a single index, - // or it may be a nil expression for the length of the string. - Expression* end_; -}; - -// String index traversal. - -int -String_index_expression::do_traverse(Traverse* traverse) -{ - if (Expression::traverse(&this->string_, traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - if (Expression::traverse(&this->start_, traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - if (this->end_ != NULL) - { - if (Expression::traverse(&this->end_, traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - return TRAVERSE_CONTINUE; -} - -// Return the type of a string index. - -Type* -String_index_expression::do_type() -{ - if (this->end_ == NULL) - return Type::lookup_integer_type("uint8"); - else - return this->string_->type(); -} - -// Determine the type of a string index. - -void -String_index_expression::do_determine_type(const Type_context*) -{ - this->string_->determine_type_no_context(); - this->start_->determine_type_no_context(); - if (this->end_ != NULL) - this->end_->determine_type_no_context(); -} - -// Check types of a string index. - -void -String_index_expression::do_check_types(Gogo*) -{ - if (this->start_->type()->integer_type() == NULL) - this->report_error(_("index must be integer")); - if (this->end_ != NULL - && this->end_->type()->integer_type() == NULL - && !this->end_->is_nil_expression()) - this->report_error(_("slice end must be integer")); - - std::string sval; - bool sval_valid = this->string_->string_constant_value(&sval); - - Numeric_constant inc; - mpz_t ival; - bool ival_valid = false; - if (this->start_->numeric_constant_value(&inc) && inc.to_int(&ival)) - { - ival_valid = true; - if (mpz_sgn(ival) < 0 - || (sval_valid && mpz_cmp_ui(ival, sval.length()) >= 0)) - { - error_at(this->start_->location(), "string index out of bounds"); - this->set_is_error(); - } - } - if (this->end_ != NULL && !this->end_->is_nil_expression()) - { - Numeric_constant enc; - mpz_t eval; - if (this->end_->numeric_constant_value(&enc) && enc.to_int(&eval)) - { - if (mpz_sgn(eval) < 0 - || (sval_valid && mpz_cmp_ui(eval, sval.length()) > 0)) - { - error_at(this->end_->location(), "string index out of bounds"); - this->set_is_error(); - } - else if (ival_valid && mpz_cmp(ival, eval) > 0) - this->report_error(_("inverted slice range")); - mpz_clear(eval); - } - } - if (ival_valid) - mpz_clear(ival); -} - -// Get a tree for a string index. - -tree -String_index_expression::do_get_tree(Translate_context* context) -{ - Location loc = this->location(); - - tree string_tree = this->string_->get_tree(context); - if (string_tree == error_mark_node) - return error_mark_node; - - if (this->string_->type()->points_to() != NULL) - string_tree = build_fold_indirect_ref(string_tree); - if (!DECL_P(string_tree)) - string_tree = save_expr(string_tree); - tree string_type = TREE_TYPE(string_tree); - - tree length_tree = String_type::length_tree(context->gogo(), string_tree); - length_tree = save_expr(length_tree); - - Type* int_type = Type::lookup_integer_type("int"); - tree length_type = type_to_tree(int_type->get_backend(context->gogo())); - - tree bad_index = boolean_false_node; - - tree start_tree = this->start_->get_tree(context); - if (start_tree == error_mark_node) - return error_mark_node; - if (!DECL_P(start_tree)) - start_tree = save_expr(start_tree); - if (!INTEGRAL_TYPE_P(TREE_TYPE(start_tree))) - start_tree = convert_to_integer(length_type, start_tree); - - bad_index = Expression::check_bounds(start_tree, length_type, bad_index, - loc); - - start_tree = fold_convert_loc(loc.gcc_location(), length_type, start_tree); - - int code = (this->end_ == NULL - ? RUNTIME_ERROR_STRING_INDEX_OUT_OF_BOUNDS - : RUNTIME_ERROR_STRING_SLICE_OUT_OF_BOUNDS); - tree crash = context->gogo()->runtime_error(code, loc); - - if (this->end_ == NULL) - { - bad_index = fold_build2_loc(loc.gcc_location(), TRUTH_OR_EXPR, - boolean_type_node, bad_index, - fold_build2_loc(loc.gcc_location(), GE_EXPR, - boolean_type_node, - start_tree, length_tree)); - - tree bytes_tree = String_type::bytes_tree(context->gogo(), string_tree); - tree ptr = fold_build2_loc(loc.gcc_location(), POINTER_PLUS_EXPR, - TREE_TYPE(bytes_tree), - bytes_tree, - fold_convert_loc(loc.gcc_location(), sizetype, - start_tree)); - tree index = build_fold_indirect_ref_loc(loc.gcc_location(), ptr); - - return build2(COMPOUND_EXPR, TREE_TYPE(index), - build3(COND_EXPR, void_type_node, - bad_index, crash, NULL_TREE), - index); - } - else - { - tree end_tree; - if (this->end_->is_nil_expression()) - end_tree = build_int_cst(length_type, -1); - else - { - end_tree = this->end_->get_tree(context); - if (end_tree == error_mark_node) - return error_mark_node; - if (!DECL_P(end_tree)) - end_tree = save_expr(end_tree); - if (!INTEGRAL_TYPE_P(TREE_TYPE(end_tree))) - end_tree = convert_to_integer(length_type, end_tree); - - bad_index = Expression::check_bounds(end_tree, length_type, - bad_index, loc); - - end_tree = fold_convert_loc(loc.gcc_location(), length_type, - end_tree); - } - - static tree strslice_fndecl; - tree ret = Gogo::call_builtin(&strslice_fndecl, - loc, - "__go_string_slice", - 3, - string_type, - string_type, - string_tree, - length_type, - start_tree, - length_type, - end_tree); - if (ret == error_mark_node) - return error_mark_node; - // This will panic if the bounds are out of range for the - // string. - TREE_NOTHROW(strslice_fndecl) = 0; - - if (bad_index == boolean_false_node) - return ret; - else - return build2(COMPOUND_EXPR, TREE_TYPE(ret), - build3(COND_EXPR, void_type_node, - bad_index, crash, NULL_TREE), - ret); - } -} - -// Dump ast representation for a string index expression. - -void -String_index_expression::do_dump_expression(Ast_dump_context* ast_dump_context) - const -{ - Index_expression::dump_index_expression(ast_dump_context, this->string_, - this->start_, this->end_); -} - -// Make a string index expression. END may be NULL. - -Expression* -Expression::make_string_index(Expression* string, Expression* start, - Expression* end, Location location) -{ - return new String_index_expression(string, start, end, location); -} - -// Class Map_index. - -// Get the type of the map. - -Map_type* -Map_index_expression::get_map_type() const -{ - Map_type* mt = this->map_->type()->deref()->map_type(); - if (mt == NULL) - go_assert(saw_errors()); - return mt; -} - -// Map index traversal. - -int -Map_index_expression::do_traverse(Traverse* traverse) -{ - if (Expression::traverse(&this->map_, traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - return Expression::traverse(&this->index_, traverse); -} - -// Return the type of a map index. - -Type* -Map_index_expression::do_type() -{ - Map_type* mt = this->get_map_type(); - if (mt == NULL) - return Type::make_error_type(); - Type* type = mt->val_type(); - // If this map index is in a tuple assignment, we actually return a - // pointer to the value type. Tuple_map_assignment_statement is - // responsible for handling this correctly. We need to get the type - // right in case this gets assigned to a temporary variable. - if (this->is_in_tuple_assignment_) - type = Type::make_pointer_type(type); - return type; -} - -// Fix the type of a map index. - -void -Map_index_expression::do_determine_type(const Type_context*) -{ - this->map_->determine_type_no_context(); - Map_type* mt = this->get_map_type(); - Type* key_type = mt == NULL ? NULL : mt->key_type(); - Type_context subcontext(key_type, false); - this->index_->determine_type(&subcontext); -} - -// Check types of a map index. - -void -Map_index_expression::do_check_types(Gogo*) -{ - std::string reason; - Map_type* mt = this->get_map_type(); - if (mt == NULL) - return; - if (!Type::are_assignable(mt->key_type(), this->index_->type(), &reason)) - { - if (reason.empty()) - this->report_error(_("incompatible type for map index")); - else - { - error_at(this->location(), "incompatible type for map index (%s)", - reason.c_str()); - this->set_is_error(); - } - } -} - -// Get a tree for a map index. - -tree -Map_index_expression::do_get_tree(Translate_context* context) -{ - Map_type* type = this->get_map_type(); - if (type == NULL) - return error_mark_node; - - tree valptr = this->get_value_pointer(context, this->is_lvalue_); - if (valptr == error_mark_node) - return error_mark_node; - valptr = save_expr(valptr); - - tree val_type_tree = TREE_TYPE(TREE_TYPE(valptr)); - - if (this->is_lvalue_) - return build_fold_indirect_ref(valptr); - else if (this->is_in_tuple_assignment_) - { - // Tuple_map_assignment_statement is responsible for using this - // appropriately. - return valptr; - } - else - { - Gogo* gogo = context->gogo(); - Btype* val_btype = type->val_type()->get_backend(gogo); - Bexpression* val_zero = gogo->backend()->zero_expression(val_btype); - return fold_build3(COND_EXPR, val_type_tree, - fold_build2(EQ_EXPR, boolean_type_node, valptr, - fold_convert(TREE_TYPE(valptr), - null_pointer_node)), - expr_to_tree(val_zero), - build_fold_indirect_ref(valptr)); - } -} - -// Get a tree for the map index. This returns a tree which evaluates -// to a pointer to a value. The pointer will be NULL if the key is -// not in the map. - -tree -Map_index_expression::get_value_pointer(Translate_context* context, - bool insert) -{ - Map_type* type = this->get_map_type(); - if (type == NULL) - return error_mark_node; - - tree map_tree = this->map_->get_tree(context); - tree index_tree = this->index_->get_tree(context); - index_tree = Expression::convert_for_assignment(context, type->key_type(), - this->index_->type(), - index_tree, - this->location()); - if (map_tree == error_mark_node || index_tree == error_mark_node) - return error_mark_node; - - if (this->map_->type()->points_to() != NULL) - map_tree = build_fold_indirect_ref(map_tree); - - // We need to pass in a pointer to the key, so stuff it into a - // variable. - tree tmp; - tree make_tmp; - if (current_function_decl != NULL) - { - tmp = create_tmp_var(TREE_TYPE(index_tree), get_name(index_tree)); - DECL_IGNORED_P(tmp) = 0; - DECL_INITIAL(tmp) = index_tree; - make_tmp = build1(DECL_EXPR, void_type_node, tmp); - TREE_ADDRESSABLE(tmp) = 1; - } - else - { - tmp = build_decl(this->location().gcc_location(), VAR_DECL, - create_tmp_var_name("M"), - TREE_TYPE(index_tree)); - DECL_EXTERNAL(tmp) = 0; - TREE_PUBLIC(tmp) = 0; - TREE_STATIC(tmp) = 1; - DECL_ARTIFICIAL(tmp) = 1; - if (!TREE_CONSTANT(index_tree)) - make_tmp = fold_build2_loc(this->location().gcc_location(), - INIT_EXPR, void_type_node, - tmp, index_tree); - else - { - TREE_READONLY(tmp) = 1; - TREE_CONSTANT(tmp) = 1; - DECL_INITIAL(tmp) = index_tree; - make_tmp = NULL_TREE; - } - rest_of_decl_compilation(tmp, 1, 0); - } - tree tmpref = - fold_convert_loc(this->location().gcc_location(), const_ptr_type_node, - build_fold_addr_expr_loc(this->location().gcc_location(), - tmp)); - - static tree map_index_fndecl; - tree call = Gogo::call_builtin(&map_index_fndecl, - this->location(), - "__go_map_index", - 3, - const_ptr_type_node, - TREE_TYPE(map_tree), - map_tree, - const_ptr_type_node, - tmpref, - boolean_type_node, - (insert - ? boolean_true_node - : boolean_false_node)); - if (call == error_mark_node) - return error_mark_node; - // This can panic on a map of interface type if the interface holds - // an uncomparable or unhashable type. - TREE_NOTHROW(map_index_fndecl) = 0; - - Type* val_type = type->val_type(); - tree val_type_tree = type_to_tree(val_type->get_backend(context->gogo())); - if (val_type_tree == error_mark_node) - return error_mark_node; - tree ptr_val_type_tree = build_pointer_type(val_type_tree); - - tree ret = fold_convert_loc(this->location().gcc_location(), - ptr_val_type_tree, call); - if (make_tmp != NULL_TREE) - ret = build2(COMPOUND_EXPR, ptr_val_type_tree, make_tmp, ret); - return ret; -} - -// Dump ast representation for a map index expression - -void -Map_index_expression::do_dump_expression(Ast_dump_context* ast_dump_context) - const -{ - Index_expression::dump_index_expression(ast_dump_context, - this->map_, this->index_, NULL); -} - -// Make a map index expression. - -Map_index_expression* -Expression::make_map_index(Expression* map, Expression* index, - Location location) -{ - return new Map_index_expression(map, index, location); -} - -// Class Field_reference_expression. - -// Lower a field reference expression. There is nothing to lower, but -// this is where we generate the tracking information for fields with -// the magic go:"track" tag. - -Expression* -Field_reference_expression::do_lower(Gogo* gogo, Named_object* function, - Statement_inserter* inserter, int) -{ - Struct_type* struct_type = this->expr_->type()->struct_type(); - if (struct_type == NULL) - { - // Error will be reported elsewhere. - return this; - } - const Struct_field* field = struct_type->field(this->field_index_); - if (field == NULL) - return this; - if (!field->has_tag()) - return this; - if (field->tag().find("go:\"track\"") == std::string::npos) - return this; - - // We have found a reference to a tracked field. Build a call to - // the runtime function __go_fieldtrack with a string that describes - // the field. FIXME: We should only call this once per referenced - // field per function, not once for each reference to the field. - - if (this->called_fieldtrack_) - return this; - this->called_fieldtrack_ = true; - - Location loc = this->location(); - - std::string s = "fieldtrack \""; - Named_type* nt = this->expr_->type()->named_type(); - if (nt == NULL || nt->named_object()->package() == NULL) - s.append(gogo->pkgpath()); - else - s.append(nt->named_object()->package()->pkgpath()); - s.push_back('.'); - if (nt != NULL) - s.append(Gogo::unpack_hidden_name(nt->name())); - s.push_back('.'); - s.append(field->field_name()); - s.push_back('"'); - - // We can't use a string here, because internally a string holds a - // pointer to the actual bytes; when the linker garbage collects the - // string, it won't garbage collect the bytes. So we use a - // [...]byte. - - mpz_t val; - mpz_init_set_ui(val, s.length()); - Expression* length_expr = Expression::make_integer(&val, NULL, loc); - mpz_clear(val); - - Type* byte_type = gogo->lookup_global("byte")->type_value(); - Type* array_type = Type::make_array_type(byte_type, length_expr); - - Expression_list* bytes = new Expression_list(); - for (std::string::const_iterator p = s.begin(); p != s.end(); p++) - { - mpz_init_set_ui(val, *p); - Expression* byte = Expression::make_integer(&val, NULL, loc); - mpz_clear(val); - bytes->push_back(byte); - } - - Expression* e = Expression::make_composite_literal(array_type, 0, false, - bytes, loc); - - Variable* var = new Variable(array_type, e, true, false, false, loc); - - static int count; - char buf[50]; - snprintf(buf, sizeof buf, "fieldtrack.%d", count); - ++count; - - Named_object* no = gogo->add_variable(buf, var); - e = Expression::make_var_reference(no, loc); - e = Expression::make_unary(OPERATOR_AND, e, loc); - - Expression* call = Runtime::make_call(Runtime::FIELDTRACK, loc, 1, e); - inserter->insert(Statement::make_statement(call, false)); - - // Put this function, and the global variable we just created, into - // unique sections. This will permit the linker to garbage collect - // them if they are not referenced. The effect is that the only - // strings, indicating field references, that will wind up in the - // executable will be those for functions that are actually needed. - if (function != NULL) - function->func_value()->set_in_unique_section(); - var->set_in_unique_section(); - - return this; -} - -// Return the type of a field reference. - -Type* -Field_reference_expression::do_type() -{ - Type* type = this->expr_->type(); - if (type->is_error()) - return type; - Struct_type* struct_type = type->struct_type(); - go_assert(struct_type != NULL); - return struct_type->field(this->field_index_)->type(); -} - -// Check the types for a field reference. - -void -Field_reference_expression::do_check_types(Gogo*) -{ - Type* type = this->expr_->type(); - if (type->is_error()) - return; - Struct_type* struct_type = type->struct_type(); - go_assert(struct_type != NULL); - go_assert(struct_type->field(this->field_index_) != NULL); -} - -// Get a tree for a field reference. - -tree -Field_reference_expression::do_get_tree(Translate_context* context) -{ - tree struct_tree = this->expr_->get_tree(context); - if (struct_tree == error_mark_node - || TREE_TYPE(struct_tree) == error_mark_node) - return error_mark_node; - go_assert(TREE_CODE(TREE_TYPE(struct_tree)) == RECORD_TYPE); - tree field = TYPE_FIELDS(TREE_TYPE(struct_tree)); - if (field == NULL_TREE) - { - // This can happen for a type which refers to itself indirectly - // and then turns out to be erroneous. - go_assert(saw_errors()); - return error_mark_node; - } - for (unsigned int i = this->field_index_; i > 0; --i) - { - field = DECL_CHAIN(field); - go_assert(field != NULL_TREE); - } - if (TREE_TYPE(field) == error_mark_node) - return error_mark_node; - return build3(COMPONENT_REF, TREE_TYPE(field), struct_tree, field, - NULL_TREE); -} - -// Dump ast representation for a field reference expression. - -void -Field_reference_expression::do_dump_expression( - Ast_dump_context* ast_dump_context) const -{ - this->expr_->dump_expression(ast_dump_context); - ast_dump_context->ostream() << "." << this->field_index_; -} - -// Make a reference to a qualified identifier in an expression. - -Field_reference_expression* -Expression::make_field_reference(Expression* expr, unsigned int field_index, - Location location) -{ - return new Field_reference_expression(expr, field_index, location); -} - -// Class Interface_field_reference_expression. - -// Return a tree for the pointer to the function to call. - -tree -Interface_field_reference_expression::get_function_tree(Translate_context*, - tree expr) -{ - if (this->expr_->type()->points_to() != NULL) - expr = build_fold_indirect_ref(expr); - - tree expr_type = TREE_TYPE(expr); - go_assert(TREE_CODE(expr_type) == RECORD_TYPE); - - tree field = TYPE_FIELDS(expr_type); - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__methods") == 0); - - tree table = build3(COMPONENT_REF, TREE_TYPE(field), expr, field, NULL_TREE); - go_assert(POINTER_TYPE_P(TREE_TYPE(table))); - - table = build_fold_indirect_ref(table); - go_assert(TREE_CODE(TREE_TYPE(table)) == RECORD_TYPE); - - std::string name = Gogo::unpack_hidden_name(this->name_); - for (field = DECL_CHAIN(TYPE_FIELDS(TREE_TYPE(table))); - field != NULL_TREE; - field = DECL_CHAIN(field)) - { - if (name == IDENTIFIER_POINTER(DECL_NAME(field))) - break; - } - go_assert(field != NULL_TREE); - - return build3(COMPONENT_REF, TREE_TYPE(field), table, field, NULL_TREE); -} - -// Return a tree for the first argument to pass to the interface -// function. - -tree -Interface_field_reference_expression::get_underlying_object_tree( - Translate_context*, - tree expr) -{ - if (this->expr_->type()->points_to() != NULL) - expr = build_fold_indirect_ref(expr); - - tree expr_type = TREE_TYPE(expr); - go_assert(TREE_CODE(expr_type) == RECORD_TYPE); - - tree field = DECL_CHAIN(TYPE_FIELDS(expr_type)); - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__object") == 0); - - return build3(COMPONENT_REF, TREE_TYPE(field), expr, field, NULL_TREE); -} - -// Traversal. - -int -Interface_field_reference_expression::do_traverse(Traverse* traverse) -{ - return Expression::traverse(&this->expr_, traverse); -} - -// Return the type of an interface field reference. - -Type* -Interface_field_reference_expression::do_type() -{ - Type* expr_type = this->expr_->type(); - - Type* points_to = expr_type->points_to(); - if (points_to != NULL) - expr_type = points_to; - - Interface_type* interface_type = expr_type->interface_type(); - if (interface_type == NULL) - return Type::make_error_type(); - - const Typed_identifier* method = interface_type->find_method(this->name_); - if (method == NULL) - return Type::make_error_type(); - - return method->type(); -} - -// Determine types. - -void -Interface_field_reference_expression::do_determine_type(const Type_context*) -{ - this->expr_->determine_type_no_context(); -} - -// Check the types for an interface field reference. - -void -Interface_field_reference_expression::do_check_types(Gogo*) -{ - Type* type = this->expr_->type(); - - Type* points_to = type->points_to(); - if (points_to != NULL) - type = points_to; - - Interface_type* interface_type = type->interface_type(); - if (interface_type == NULL) - { - if (!type->is_error_type()) - this->report_error(_("expected interface or pointer to interface")); - } - else - { - const Typed_identifier* method = - interface_type->find_method(this->name_); - if (method == NULL) - { - error_at(this->location(), "method %qs not in interface", - Gogo::message_name(this->name_).c_str()); - this->set_is_error(); - } - } -} - -// Get a tree for a reference to a field in an interface. There is no -// standard tree type representation for this: it's a function -// attached to its first argument, like a Bound_method_expression. -// The only places it may currently be used are in a Call_expression -// or a Go_statement, which will take it apart directly. So this has -// nothing to do at present. - -tree -Interface_field_reference_expression::do_get_tree(Translate_context*) -{ - error_at(this->location(), "reference to method other than calling it"); - return error_mark_node; -} - -// Dump ast representation for an interface field reference. - -void -Interface_field_reference_expression::do_dump_expression( - Ast_dump_context* ast_dump_context) const -{ - this->expr_->dump_expression(ast_dump_context); - ast_dump_context->ostream() << "." << this->name_; -} - -// Make a reference to a field in an interface. - -Expression* -Expression::make_interface_field_reference(Expression* expr, - const std::string& field, - Location location) -{ - return new Interface_field_reference_expression(expr, field, location); -} - -// A general selector. This is a Parser_expression for LEFT.NAME. It -// is lowered after we know the type of the left hand side. - -class Selector_expression : public Parser_expression -{ - public: - Selector_expression(Expression* left, const std::string& name, - Location location) - : Parser_expression(EXPRESSION_SELECTOR, location), - left_(left), name_(name) - { } - - protected: - int - do_traverse(Traverse* traverse) - { return Expression::traverse(&this->left_, traverse); } - - Expression* - do_lower(Gogo*, Named_object*, Statement_inserter*, int); - - Expression* - do_copy() - { - return new Selector_expression(this->left_->copy(), this->name_, - this->location()); - } - - void - do_dump_expression(Ast_dump_context* ast_dump_context) const; - - private: - Expression* - lower_method_expression(Gogo*); - - // The expression on the left hand side. - Expression* left_; - // The name on the right hand side. - std::string name_; -}; - -// Lower a selector expression once we know the real type of the left -// hand side. - -Expression* -Selector_expression::do_lower(Gogo* gogo, Named_object*, Statement_inserter*, - int) -{ - Expression* left = this->left_; - if (left->is_type_expression()) - return this->lower_method_expression(gogo); - return Type::bind_field_or_method(gogo, left->type(), left, this->name_, - this->location()); -} - -// Lower a method expression T.M or (*T).M. We turn this into a -// function literal. - -Expression* -Selector_expression::lower_method_expression(Gogo* gogo) -{ - Location location = this->location(); - Type* type = this->left_->type(); - const std::string& name(this->name_); - - bool is_pointer; - if (type->points_to() == NULL) - is_pointer = false; - else - { - is_pointer = true; - type = type->points_to(); - } - Named_type* nt = type->named_type(); - if (nt == NULL) - { - error_at(location, - ("method expression requires named type or " - "pointer to named type")); - return Expression::make_error(location); - } - - bool is_ambiguous; - Method* method = nt->method_function(name, &is_ambiguous); - const Typed_identifier* imethod = NULL; - if (method == NULL && !is_pointer) - { - Interface_type* it = nt->interface_type(); - if (it != NULL) - imethod = it->find_method(name); - } - - if (method == NULL && imethod == NULL) - { - if (!is_ambiguous) - error_at(location, "type %<%s%s%> has no method %<%s%>", - is_pointer ? "*" : "", - nt->message_name().c_str(), - Gogo::message_name(name).c_str()); - else - error_at(location, "method %<%s%s%> is ambiguous in type %<%s%>", - Gogo::message_name(name).c_str(), - is_pointer ? "*" : "", - nt->message_name().c_str()); - return Expression::make_error(location); - } - - if (method != NULL && !is_pointer && !method->is_value_method()) - { - error_at(location, "method requires pointer (use %<(*%s).%s)%>", - nt->message_name().c_str(), - Gogo::message_name(name).c_str()); - return Expression::make_error(location); - } - - // Build a new function type in which the receiver becomes the first - // argument. - Function_type* method_type; - if (method != NULL) - { - method_type = method->type(); - go_assert(method_type->is_method()); - } - else - { - method_type = imethod->type()->function_type(); - go_assert(method_type != NULL && !method_type->is_method()); - } - - const char* const receiver_name = "$this"; - Typed_identifier_list* parameters = new Typed_identifier_list(); - parameters->push_back(Typed_identifier(receiver_name, this->left_->type(), - location)); - - const Typed_identifier_list* method_parameters = method_type->parameters(); - if (method_parameters != NULL) - { - int i = 0; - for (Typed_identifier_list::const_iterator p = method_parameters->begin(); - p != method_parameters->end(); - ++p, ++i) - { - if (!p->name().empty()) - parameters->push_back(*p); - else - { - char buf[20]; - snprintf(buf, sizeof buf, "$param%d", i); - parameters->push_back(Typed_identifier(buf, p->type(), - p->location())); - } - } - } - - const Typed_identifier_list* method_results = method_type->results(); - Typed_identifier_list* results; - if (method_results == NULL) - results = NULL; - else - { - results = new Typed_identifier_list(); - for (Typed_identifier_list::const_iterator p = method_results->begin(); - p != method_results->end(); - ++p) - results->push_back(*p); - } - - Function_type* fntype = Type::make_function_type(NULL, parameters, results, - location); - if (method_type->is_varargs()) - fntype->set_is_varargs(); - - // We generate methods which always takes a pointer to the receiver - // as their first argument. If this is for a pointer type, we can - // simply reuse the existing function. We use an internal hack to - // get the right type. - - if (method != NULL && is_pointer) - { - Named_object* mno = (method->needs_stub_method() - ? method->stub_object() - : method->named_object()); - Expression* f = Expression::make_func_reference(mno, NULL, location); - f = Expression::make_cast(fntype, f, location); - Type_conversion_expression* tce = - static_cast<Type_conversion_expression*>(f); - tce->set_may_convert_function_types(); - return f; - } - - Named_object* no = gogo->start_function(Gogo::thunk_name(), fntype, false, - location); - - Named_object* vno = gogo->lookup(receiver_name, NULL); - go_assert(vno != NULL); - Expression* ve = Expression::make_var_reference(vno, location); - Expression* bm; - if (method != NULL) - bm = Type::bind_field_or_method(gogo, nt, ve, name, location); - else - bm = Expression::make_interface_field_reference(ve, name, location); - - // Even though we found the method above, if it has an error type we - // may see an error here. - if (bm->is_error_expression()) - { - gogo->finish_function(location); - return bm; - } - - Expression_list* args; - if (parameters->size() <= 1) - args = NULL; - else - { - args = new Expression_list(); - Typed_identifier_list::const_iterator p = parameters->begin(); - ++p; - for (; p != parameters->end(); ++p) - { - vno = gogo->lookup(p->name(), NULL); - go_assert(vno != NULL); - args->push_back(Expression::make_var_reference(vno, location)); - } - } - - gogo->start_block(location); - - Call_expression* call = Expression::make_call(bm, args, - method_type->is_varargs(), - location); - - size_t count = call->result_count(); - Statement* s; - if (count == 0) - s = Statement::make_statement(call, true); - else - { - Expression_list* retvals = new Expression_list(); - if (count <= 1) - retvals->push_back(call); - else - { - for (size_t i = 0; i < count; ++i) - retvals->push_back(Expression::make_call_result(call, i)); - } - s = Statement::make_return_statement(retvals, location); - } - gogo->add_statement(s); - - Block* b = gogo->finish_block(location); - - gogo->add_block(b, location); - - // Lower the call in case there are multiple results. - gogo->lower_block(no, b); - - gogo->finish_function(location); - - return Expression::make_func_reference(no, NULL, location); -} - -// Dump the ast for a selector expression. - -void -Selector_expression::do_dump_expression(Ast_dump_context* ast_dump_context) - const -{ - ast_dump_context->dump_expression(this->left_); - ast_dump_context->ostream() << "."; - ast_dump_context->ostream() << this->name_; -} - -// Make a selector expression. - -Expression* -Expression::make_selector(Expression* left, const std::string& name, - Location location) -{ - return new Selector_expression(left, name, location); -} - -// Implement the builtin function new. - -class Allocation_expression : public Expression -{ - public: - Allocation_expression(Type* type, Location location) - : Expression(EXPRESSION_ALLOCATION, location), - type_(type) - { } - - protected: - int - do_traverse(Traverse* traverse) - { return Type::traverse(this->type_, traverse); } - - Type* - do_type() - { return Type::make_pointer_type(this->type_); } - - void - do_determine_type(const Type_context*) - { } - - Expression* - do_copy() - { return new Allocation_expression(this->type_, this->location()); } - - tree - do_get_tree(Translate_context*); - - void - do_dump_expression(Ast_dump_context*) const; - - private: - // The type we are allocating. - Type* type_; -}; - -// Return a tree for an allocation expression. - -tree -Allocation_expression::do_get_tree(Translate_context* context) -{ - tree type_tree = type_to_tree(this->type_->get_backend(context->gogo())); - if (type_tree == error_mark_node) - return error_mark_node; - tree size_tree = TYPE_SIZE_UNIT(type_tree); - tree space = context->gogo()->allocate_memory(this->type_, size_tree, - this->location()); - if (space == error_mark_node) - return error_mark_node; - return fold_convert(build_pointer_type(type_tree), space); -} - -// Dump ast representation for an allocation expression. - -void -Allocation_expression::do_dump_expression(Ast_dump_context* ast_dump_context) - const -{ - ast_dump_context->ostream() << "new("; - ast_dump_context->dump_type(this->type_); - ast_dump_context->ostream() << ")"; -} - -// Make an allocation expression. - -Expression* -Expression::make_allocation(Type* type, Location location) -{ - return new Allocation_expression(type, location); -} - -// Construct a struct. - -class Struct_construction_expression : public Expression -{ - public: - Struct_construction_expression(Type* type, Expression_list* vals, - Location location) - : Expression(EXPRESSION_STRUCT_CONSTRUCTION, location), - type_(type), vals_(vals), traverse_order_(NULL) - { } - - // Set the traversal order, used to ensure that we implement the - // order of evaluation rules. Takes ownership of the argument. - void - set_traverse_order(std::vector<int>* traverse_order) - { this->traverse_order_ = traverse_order; } - - // Return whether this is a constant initializer. - bool - is_constant_struct() const; - - protected: - int - do_traverse(Traverse* traverse); - - Type* - do_type() - { return this->type_; } - - void - do_determine_type(const Type_context*); - - void - do_check_types(Gogo*); - - Expression* - do_copy() - { - Struct_construction_expression* ret = - new Struct_construction_expression(this->type_, this->vals_->copy(), - this->location()); - if (this->traverse_order_ != NULL) - ret->set_traverse_order(this->traverse_order_); - return ret; - } - - tree - do_get_tree(Translate_context*); - - void - do_export(Export*) const; - - void - do_dump_expression(Ast_dump_context*) const; - - private: - // The type of the struct to construct. - Type* type_; - // The list of values, in order of the fields in the struct. A NULL - // entry means that the field should be zero-initialized. - Expression_list* vals_; - // If not NULL, the order in which to traverse vals_. This is used - // so that we implement the order of evaluation rules correctly. - std::vector<int>* traverse_order_; -}; - -// Traversal. - -int -Struct_construction_expression::do_traverse(Traverse* traverse) -{ - if (this->vals_ != NULL) - { - if (this->traverse_order_ == NULL) - { - if (this->vals_->traverse(traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - else - { - for (std::vector<int>::const_iterator p = - this->traverse_order_->begin(); - p != this->traverse_order_->end(); - ++p) - { - if (Expression::traverse(&this->vals_->at(*p), traverse) - == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - } - } - if (Type::traverse(this->type_, traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - return TRAVERSE_CONTINUE; -} - -// Return whether this is a constant initializer. - -bool -Struct_construction_expression::is_constant_struct() const -{ - if (this->vals_ == NULL) - return true; - for (Expression_list::const_iterator pv = this->vals_->begin(); - pv != this->vals_->end(); - ++pv) - { - if (*pv != NULL - && !(*pv)->is_constant() - && (!(*pv)->is_composite_literal() - || (*pv)->is_nonconstant_composite_literal())) - return false; - } - - const Struct_field_list* fields = this->type_->struct_type()->fields(); - for (Struct_field_list::const_iterator pf = fields->begin(); - pf != fields->end(); - ++pf) - { - // There are no constant constructors for interfaces. - if (pf->type()->interface_type() != NULL) - return false; - } - - return true; -} - -// Final type determination. - -void -Struct_construction_expression::do_determine_type(const Type_context*) -{ - if (this->vals_ == NULL) - return; - const Struct_field_list* fields = this->type_->struct_type()->fields(); - Expression_list::const_iterator pv = this->vals_->begin(); - for (Struct_field_list::const_iterator pf = fields->begin(); - pf != fields->end(); - ++pf, ++pv) - { - if (pv == this->vals_->end()) - return; - if (*pv != NULL) - { - Type_context subcontext(pf->type(), false); - (*pv)->determine_type(&subcontext); - } - } - // Extra values are an error we will report elsewhere; we still want - // to determine the type to avoid knockon errors. - for (; pv != this->vals_->end(); ++pv) - (*pv)->determine_type_no_context(); -} - -// Check types. - -void -Struct_construction_expression::do_check_types(Gogo*) -{ - if (this->vals_ == NULL) - return; - - Struct_type* st = this->type_->struct_type(); - if (this->vals_->size() > st->field_count()) - { - this->report_error(_("too many expressions for struct")); - return; - } - - const Struct_field_list* fields = st->fields(); - Expression_list::const_iterator pv = this->vals_->begin(); - int i = 0; - for (Struct_field_list::const_iterator pf = fields->begin(); - pf != fields->end(); - ++pf, ++pv, ++i) - { - if (pv == this->vals_->end()) - { - this->report_error(_("too few expressions for struct")); - break; - } - - if (*pv == NULL) - continue; - - std::string reason; - if (!Type::are_assignable(pf->type(), (*pv)->type(), &reason)) - { - if (reason.empty()) - error_at((*pv)->location(), - "incompatible type for field %d in struct construction", - i + 1); - else - error_at((*pv)->location(), - ("incompatible type for field %d in " - "struct construction (%s)"), - i + 1, reason.c_str()); - this->set_is_error(); - } - } - go_assert(pv == this->vals_->end()); -} - -// Return a tree for constructing a struct. - -tree -Struct_construction_expression::do_get_tree(Translate_context* context) -{ - Gogo* gogo = context->gogo(); - - if (this->vals_ == NULL) - { - Btype* btype = this->type_->get_backend(gogo); - return expr_to_tree(gogo->backend()->zero_expression(btype)); - } - - tree type_tree = type_to_tree(this->type_->get_backend(gogo)); - if (type_tree == error_mark_node) - return error_mark_node; - go_assert(TREE_CODE(type_tree) == RECORD_TYPE); - - bool is_constant = true; - const Struct_field_list* fields = this->type_->struct_type()->fields(); - vec<constructor_elt, va_gc> *elts; - vec_alloc (elts, fields->size()); - Struct_field_list::const_iterator pf = fields->begin(); - Expression_list::const_iterator pv = this->vals_->begin(); - for (tree field = TYPE_FIELDS(type_tree); - field != NULL_TREE; - field = DECL_CHAIN(field), ++pf) - { - go_assert(pf != fields->end()); - - Btype* fbtype = pf->type()->get_backend(gogo); - - tree val; - if (pv == this->vals_->end()) - val = expr_to_tree(gogo->backend()->zero_expression(fbtype)); - else if (*pv == NULL) - { - val = expr_to_tree(gogo->backend()->zero_expression(fbtype)); - ++pv; - } - else - { - val = Expression::convert_for_assignment(context, pf->type(), - (*pv)->type(), - (*pv)->get_tree(context), - this->location()); - ++pv; - } - - if (val == error_mark_node || TREE_TYPE(val) == error_mark_node) - return error_mark_node; - - constructor_elt empty = {NULL, NULL}; - constructor_elt* elt = elts->quick_push(empty); - elt->index = field; - elt->value = val; - if (!TREE_CONSTANT(val)) - is_constant = false; - } - go_assert(pf == fields->end()); - - tree ret = build_constructor(type_tree, elts); - if (is_constant) - TREE_CONSTANT(ret) = 1; - return ret; -} - -// Export a struct construction. - -void -Struct_construction_expression::do_export(Export* exp) const -{ - exp->write_c_string("convert("); - exp->write_type(this->type_); - for (Expression_list::const_iterator pv = this->vals_->begin(); - pv != this->vals_->end(); - ++pv) - { - exp->write_c_string(", "); - if (*pv != NULL) - (*pv)->export_expression(exp); - } - exp->write_c_string(")"); -} - -// Dump ast representation of a struct construction expression. - -void -Struct_construction_expression::do_dump_expression( - Ast_dump_context* ast_dump_context) const -{ - ast_dump_context->dump_type(this->type_); - ast_dump_context->ostream() << "{"; - ast_dump_context->dump_expression_list(this->vals_); - ast_dump_context->ostream() << "}"; -} - -// Make a struct composite literal. This used by the thunk code. - -Expression* -Expression::make_struct_composite_literal(Type* type, Expression_list* vals, - Location location) -{ - go_assert(type->struct_type() != NULL); - return new Struct_construction_expression(type, vals, location); -} - -// Construct an array. This class is not used directly; instead we -// use the child classes, Fixed_array_construction_expression and -// Open_array_construction_expression. - -class Array_construction_expression : public Expression -{ - protected: - Array_construction_expression(Expression_classification classification, - Type* type, - const std::vector<unsigned long>* indexes, - Expression_list* vals, Location location) - : Expression(classification, location), - type_(type), indexes_(indexes), vals_(vals) - { go_assert(indexes == NULL || indexes->size() == vals->size()); } - - public: - // Return whether this is a constant initializer. - bool - is_constant_array() const; - - // Return the number of elements. - size_t - element_count() const - { return this->vals_ == NULL ? 0 : this->vals_->size(); } - -protected: - int - do_traverse(Traverse* traverse); - - Type* - do_type() - { return this->type_; } - - void - do_determine_type(const Type_context*); - - void - do_check_types(Gogo*); - - void - do_export(Export*) const; - - // The indexes. - const std::vector<unsigned long>* - indexes() - { return this->indexes_; } - - // The list of values. - Expression_list* - vals() - { return this->vals_; } - - // Get a constructor tree for the array values. - tree - get_constructor_tree(Translate_context* context, tree type_tree); - - void - do_dump_expression(Ast_dump_context*) const; - - private: - // The type of the array to construct. - Type* type_; - // The list of indexes into the array, one for each value. This may - // be NULL, in which case the indexes start at zero and increment. - const std::vector<unsigned long>* indexes_; - // The list of values. This may be NULL if there are no values. - Expression_list* vals_; -}; - -// Traversal. - -int -Array_construction_expression::do_traverse(Traverse* traverse) -{ - if (this->vals_ != NULL - && this->vals_->traverse(traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - if (Type::traverse(this->type_, traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - return TRAVERSE_CONTINUE; -} - -// Return whether this is a constant initializer. - -bool -Array_construction_expression::is_constant_array() const -{ - if (this->vals_ == NULL) - return true; - - // There are no constant constructors for interfaces. - if (this->type_->array_type()->element_type()->interface_type() != NULL) - return false; - - for (Expression_list::const_iterator pv = this->vals_->begin(); - pv != this->vals_->end(); - ++pv) - { - if (*pv != NULL - && !(*pv)->is_constant() - && (!(*pv)->is_composite_literal() - || (*pv)->is_nonconstant_composite_literal())) - return false; - } - return true; -} - -// Final type determination. - -void -Array_construction_expression::do_determine_type(const Type_context*) -{ - if (this->vals_ == NULL) - return; - Type_context subcontext(this->type_->array_type()->element_type(), false); - for (Expression_list::const_iterator pv = this->vals_->begin(); - pv != this->vals_->end(); - ++pv) - { - if (*pv != NULL) - (*pv)->determine_type(&subcontext); - } -} - -// Check types. - -void -Array_construction_expression::do_check_types(Gogo*) -{ - if (this->vals_ == NULL) - return; - - Array_type* at = this->type_->array_type(); - int i = 0; - Type* element_type = at->element_type(); - for (Expression_list::const_iterator pv = this->vals_->begin(); - pv != this->vals_->end(); - ++pv, ++i) - { - if (*pv != NULL - && !Type::are_assignable(element_type, (*pv)->type(), NULL)) - { - error_at((*pv)->location(), - "incompatible type for element %d in composite literal", - i + 1); - this->set_is_error(); - } - } -} - -// Get a constructor tree for the array values. - -tree -Array_construction_expression::get_constructor_tree(Translate_context* context, - tree type_tree) -{ - vec<constructor_elt, va_gc> *values; - vec_alloc (values, (this->vals_ == NULL ? 0 : this->vals_->size())); - Type* element_type = this->type_->array_type()->element_type(); - bool is_constant = true; - if (this->vals_ != NULL) - { - size_t i = 0; - std::vector<unsigned long>::const_iterator pi; - if (this->indexes_ != NULL) - pi = this->indexes_->begin(); - for (Expression_list::const_iterator pv = this->vals_->begin(); - pv != this->vals_->end(); - ++pv, ++i) - { - if (this->indexes_ != NULL) - go_assert(pi != this->indexes_->end()); - constructor_elt empty = {NULL, NULL}; - constructor_elt* elt = values->quick_push(empty); - - if (this->indexes_ == NULL) - elt->index = size_int(i); - else - elt->index = size_int(*pi); - - if (*pv == NULL) - { - Gogo* gogo = context->gogo(); - Btype* ebtype = element_type->get_backend(gogo); - Bexpression *zv = gogo->backend()->zero_expression(ebtype); - elt->value = expr_to_tree(zv); - } - else - { - tree value_tree = (*pv)->get_tree(context); - elt->value = Expression::convert_for_assignment(context, - element_type, - (*pv)->type(), - value_tree, - this->location()); - } - if (elt->value == error_mark_node) - return error_mark_node; - if (!TREE_CONSTANT(elt->value)) - is_constant = false; - if (this->indexes_ != NULL) - ++pi; - } - if (this->indexes_ != NULL) - go_assert(pi == this->indexes_->end()); - } - - tree ret = build_constructor(type_tree, values); - if (is_constant) - TREE_CONSTANT(ret) = 1; - return ret; -} - -// Export an array construction. - -void -Array_construction_expression::do_export(Export* exp) const -{ - exp->write_c_string("convert("); - exp->write_type(this->type_); - if (this->vals_ != NULL) - { - std::vector<unsigned long>::const_iterator pi; - if (this->indexes_ != NULL) - pi = this->indexes_->begin(); - for (Expression_list::const_iterator pv = this->vals_->begin(); - pv != this->vals_->end(); - ++pv) - { - exp->write_c_string(", "); - - if (this->indexes_ != NULL) - { - char buf[100]; - snprintf(buf, sizeof buf, "%lu", *pi); - exp->write_c_string(buf); - exp->write_c_string(":"); - } - - if (*pv != NULL) - (*pv)->export_expression(exp); - - if (this->indexes_ != NULL) - ++pi; - } - } - exp->write_c_string(")"); -} - -// Dump ast representation of an array construction expressin. - -void -Array_construction_expression::do_dump_expression( - Ast_dump_context* ast_dump_context) const -{ - Expression* length = this->type_->array_type()->length(); - - ast_dump_context->ostream() << "[" ; - if (length != NULL) - { - ast_dump_context->dump_expression(length); - } - ast_dump_context->ostream() << "]" ; - ast_dump_context->dump_type(this->type_); - ast_dump_context->ostream() << "{" ; - if (this->indexes_ == NULL) - ast_dump_context->dump_expression_list(this->vals_); - else - { - Expression_list::const_iterator pv = this->vals_->begin(); - for (std::vector<unsigned long>::const_iterator pi = - this->indexes_->begin(); - pi != this->indexes_->end(); - ++pi, ++pv) - { - if (pi != this->indexes_->begin()) - ast_dump_context->ostream() << ", "; - ast_dump_context->ostream() << *pi << ':'; - ast_dump_context->dump_expression(*pv); - } - } - ast_dump_context->ostream() << "}" ; - -} - -// Construct a fixed array. - -class Fixed_array_construction_expression : - public Array_construction_expression -{ - public: - Fixed_array_construction_expression(Type* type, - const std::vector<unsigned long>* indexes, - Expression_list* vals, Location location) - : Array_construction_expression(EXPRESSION_FIXED_ARRAY_CONSTRUCTION, - type, indexes, vals, location) - { go_assert(type->array_type() != NULL && !type->is_slice_type()); } - - protected: - Expression* - do_copy() - { - return new Fixed_array_construction_expression(this->type(), - this->indexes(), - (this->vals() == NULL - ? NULL - : this->vals()->copy()), - this->location()); - } - - tree - do_get_tree(Translate_context*); -}; - -// Return a tree for constructing a fixed array. - -tree -Fixed_array_construction_expression::do_get_tree(Translate_context* context) -{ - Type* type = this->type(); - Btype* btype = type->get_backend(context->gogo()); - return this->get_constructor_tree(context, type_to_tree(btype)); -} - -// Construct an open array. - -class Open_array_construction_expression : public Array_construction_expression -{ - public: - Open_array_construction_expression(Type* type, - const std::vector<unsigned long>* indexes, - Expression_list* vals, Location location) - : Array_construction_expression(EXPRESSION_OPEN_ARRAY_CONSTRUCTION, - type, indexes, vals, location) - { go_assert(type->is_slice_type()); } - - protected: - // Note that taking the address of an open array literal is invalid. - - Expression* - do_copy() - { - return new Open_array_construction_expression(this->type(), - this->indexes(), - (this->vals() == NULL - ? NULL - : this->vals()->copy()), - this->location()); - } - - tree - do_get_tree(Translate_context*); -}; - -// Return a tree for constructing an open array. - -tree -Open_array_construction_expression::do_get_tree(Translate_context* context) -{ - Array_type* array_type = this->type()->array_type(); - if (array_type == NULL) - { - go_assert(this->type()->is_error()); - return error_mark_node; - } - - Type* element_type = array_type->element_type(); - Btype* belement_type = element_type->get_backend(context->gogo()); - tree element_type_tree = type_to_tree(belement_type); - if (element_type_tree == error_mark_node) - return error_mark_node; - - tree values; - tree length_tree; - if (this->vals() == NULL || this->vals()->empty()) - { - // We need to create a unique value. - tree max = size_int(0); - tree constructor_type = build_array_type(element_type_tree, - build_index_type(max)); - if (constructor_type == error_mark_node) - return error_mark_node; - vec<constructor_elt, va_gc> *vec; - vec_alloc(vec, 1); - constructor_elt empty = {NULL, NULL}; - constructor_elt* elt = vec->quick_push(empty); - elt->index = size_int(0); - Gogo* gogo = context->gogo(); - Btype* btype = element_type->get_backend(gogo); - elt->value = expr_to_tree(gogo->backend()->zero_expression(btype)); - values = build_constructor(constructor_type, vec); - if (TREE_CONSTANT(elt->value)) - TREE_CONSTANT(values) = 1; - length_tree = size_int(0); - } - else - { - unsigned long max_index; - if (this->indexes() == NULL) - max_index = this->vals()->size() - 1; - else - max_index = this->indexes()->back(); - tree max_tree = size_int(max_index); - tree constructor_type = build_array_type(element_type_tree, - build_index_type(max_tree)); - if (constructor_type == error_mark_node) - return error_mark_node; - values = this->get_constructor_tree(context, constructor_type); - length_tree = size_int(max_index + 1); - } - - if (values == error_mark_node) - return error_mark_node; - - bool is_constant_initializer = TREE_CONSTANT(values); - - // We have to copy the initial values into heap memory if we are in - // a function or if the values are not constants. We also have to - // copy them if they may contain pointers in a non-constant context, - // as otherwise the garbage collector won't see them. - bool copy_to_heap = (context->function() != NULL - || !is_constant_initializer - || (element_type->has_pointer() - && !context->is_const())); - - if (is_constant_initializer) - { - tree tmp = build_decl(this->location().gcc_location(), VAR_DECL, - create_tmp_var_name("C"), TREE_TYPE(values)); - DECL_EXTERNAL(tmp) = 0; - TREE_PUBLIC(tmp) = 0; - TREE_STATIC(tmp) = 1; - DECL_ARTIFICIAL(tmp) = 1; - if (copy_to_heap) - { - // If we are not copying the value to the heap, we will only - // initialize the value once, so we can use this directly - // rather than copying it. In that case we can't make it - // read-only, because the program is permitted to change it. - TREE_READONLY(tmp) = 1; - TREE_CONSTANT(tmp) = 1; - } - DECL_INITIAL(tmp) = values; - rest_of_decl_compilation(tmp, 1, 0); - values = tmp; - } - - tree space; - tree set; - if (!copy_to_heap) - { - // the initializer will only run once. - space = build_fold_addr_expr(values); - set = NULL_TREE; - } - else - { - tree memsize = TYPE_SIZE_UNIT(TREE_TYPE(values)); - space = context->gogo()->allocate_memory(element_type, memsize, - this->location()); - space = save_expr(space); - - tree s = fold_convert(build_pointer_type(TREE_TYPE(values)), space); - tree ref = build_fold_indirect_ref_loc(this->location().gcc_location(), - s); - TREE_THIS_NOTRAP(ref) = 1; - set = build2(MODIFY_EXPR, void_type_node, ref, values); - } - - // Build a constructor for the open array. - - tree type_tree = type_to_tree(this->type()->get_backend(context->gogo())); - if (type_tree == error_mark_node) - return error_mark_node; - go_assert(TREE_CODE(type_tree) == RECORD_TYPE); - - vec<constructor_elt, va_gc> *init; - vec_alloc(init, 3); - - constructor_elt empty = {NULL, NULL}; - constructor_elt* elt = init->quick_push(empty); - tree field = TYPE_FIELDS(type_tree); - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__values") == 0); - elt->index = field; - elt->value = fold_convert(TREE_TYPE(field), space); - - elt = init->quick_push(empty); - field = DECL_CHAIN(field); - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__count") == 0); - elt->index = field; - elt->value = fold_convert(TREE_TYPE(field), length_tree); - - elt = init->quick_push(empty); - field = DECL_CHAIN(field); - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)),"__capacity") == 0); - elt->index = field; - elt->value = fold_convert(TREE_TYPE(field), length_tree); - - tree constructor = build_constructor(type_tree, init); - if (constructor == error_mark_node) - return error_mark_node; - if (!copy_to_heap) - TREE_CONSTANT(constructor) = 1; - - if (set == NULL_TREE) - return constructor; - else - return build2(COMPOUND_EXPR, type_tree, set, constructor); -} - -// Make a slice composite literal. This is used by the type -// descriptor code. - -Expression* -Expression::make_slice_composite_literal(Type* type, Expression_list* vals, - Location location) -{ - go_assert(type->is_slice_type()); - return new Open_array_construction_expression(type, NULL, vals, location); -} - -// Construct a map. - -class Map_construction_expression : public Expression -{ - public: - Map_construction_expression(Type* type, Expression_list* vals, - Location location) - : Expression(EXPRESSION_MAP_CONSTRUCTION, location), - type_(type), vals_(vals) - { go_assert(vals == NULL || vals->size() % 2 == 0); } - - protected: - int - do_traverse(Traverse* traverse); - - Type* - do_type() - { return this->type_; } - - void - do_determine_type(const Type_context*); - - void - do_check_types(Gogo*); - - Expression* - do_copy() - { - return new Map_construction_expression(this->type_, this->vals_->copy(), - this->location()); - } - - tree - do_get_tree(Translate_context*); - - void - do_export(Export*) const; - - void - do_dump_expression(Ast_dump_context*) const; - - private: - // The type of the map to construct. - Type* type_; - // The list of values. - Expression_list* vals_; -}; - -// Traversal. - -int -Map_construction_expression::do_traverse(Traverse* traverse) -{ - if (this->vals_ != NULL - && this->vals_->traverse(traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - if (Type::traverse(this->type_, traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - return TRAVERSE_CONTINUE; -} - -// Final type determination. - -void -Map_construction_expression::do_determine_type(const Type_context*) -{ - if (this->vals_ == NULL) - return; - - Map_type* mt = this->type_->map_type(); - Type_context key_context(mt->key_type(), false); - Type_context val_context(mt->val_type(), false); - for (Expression_list::const_iterator pv = this->vals_->begin(); - pv != this->vals_->end(); - ++pv) - { - (*pv)->determine_type(&key_context); - ++pv; - (*pv)->determine_type(&val_context); - } -} - -// Check types. - -void -Map_construction_expression::do_check_types(Gogo*) -{ - if (this->vals_ == NULL) - return; - - Map_type* mt = this->type_->map_type(); - int i = 0; - Type* key_type = mt->key_type(); - Type* val_type = mt->val_type(); - for (Expression_list::const_iterator pv = this->vals_->begin(); - pv != this->vals_->end(); - ++pv, ++i) - { - if (!Type::are_assignable(key_type, (*pv)->type(), NULL)) - { - error_at((*pv)->location(), - "incompatible type for element %d key in map construction", - i + 1); - this->set_is_error(); - } - ++pv; - if (!Type::are_assignable(val_type, (*pv)->type(), NULL)) - { - error_at((*pv)->location(), - ("incompatible type for element %d value " - "in map construction"), - i + 1); - this->set_is_error(); - } - } -} - -// Return a tree for constructing a map. - -tree -Map_construction_expression::do_get_tree(Translate_context* context) -{ - Gogo* gogo = context->gogo(); - Location loc = this->location(); - - Map_type* mt = this->type_->map_type(); - - // Build a struct to hold the key and value. - tree struct_type = make_node(RECORD_TYPE); - - Type* key_type = mt->key_type(); - tree id = get_identifier("__key"); - tree key_type_tree = type_to_tree(key_type->get_backend(gogo)); - if (key_type_tree == error_mark_node) - return error_mark_node; - tree key_field = build_decl(loc.gcc_location(), FIELD_DECL, id, - key_type_tree); - DECL_CONTEXT(key_field) = struct_type; - TYPE_FIELDS(struct_type) = key_field; - - Type* val_type = mt->val_type(); - id = get_identifier("__val"); - tree val_type_tree = type_to_tree(val_type->get_backend(gogo)); - if (val_type_tree == error_mark_node) - return error_mark_node; - tree val_field = build_decl(loc.gcc_location(), FIELD_DECL, id, - val_type_tree); - DECL_CONTEXT(val_field) = struct_type; - DECL_CHAIN(key_field) = val_field; - - layout_type(struct_type); - - bool is_constant = true; - size_t i = 0; - tree valaddr; - tree make_tmp; - - if (this->vals_ == NULL || this->vals_->empty()) - { - valaddr = null_pointer_node; - make_tmp = NULL_TREE; - } - else - { - vec<constructor_elt, va_gc> *values; - vec_alloc(values, this->vals_->size() / 2); - - for (Expression_list::const_iterator pv = this->vals_->begin(); - pv != this->vals_->end(); - ++pv, ++i) - { - bool one_is_constant = true; - - vec<constructor_elt, va_gc> *one; - vec_alloc(one, 2); - - constructor_elt empty = {NULL, NULL}; - constructor_elt* elt = one->quick_push(empty); - elt->index = key_field; - tree val_tree = (*pv)->get_tree(context); - elt->value = Expression::convert_for_assignment(context, key_type, - (*pv)->type(), - val_tree, loc); - if (elt->value == error_mark_node) - return error_mark_node; - if (!TREE_CONSTANT(elt->value)) - one_is_constant = false; - - ++pv; - - elt = one->quick_push(empty); - elt->index = val_field; - val_tree = (*pv)->get_tree(context); - elt->value = Expression::convert_for_assignment(context, val_type, - (*pv)->type(), - val_tree, loc); - if (elt->value == error_mark_node) - return error_mark_node; - if (!TREE_CONSTANT(elt->value)) - one_is_constant = false; - - elt = values->quick_push(empty); - elt->index = size_int(i); - elt->value = build_constructor(struct_type, one); - if (one_is_constant) - TREE_CONSTANT(elt->value) = 1; - else - is_constant = false; - } - - tree index_type = build_index_type(size_int(i - 1)); - tree array_type = build_array_type(struct_type, index_type); - tree init = build_constructor(array_type, values); - if (is_constant) - TREE_CONSTANT(init) = 1; - tree tmp; - if (current_function_decl != NULL) - { - tmp = create_tmp_var(array_type, get_name(array_type)); - DECL_INITIAL(tmp) = init; - make_tmp = fold_build1_loc(loc.gcc_location(), DECL_EXPR, - void_type_node, tmp); - TREE_ADDRESSABLE(tmp) = 1; - } - else - { - tmp = build_decl(loc.gcc_location(), VAR_DECL, - create_tmp_var_name("M"), array_type); - DECL_EXTERNAL(tmp) = 0; - TREE_PUBLIC(tmp) = 0; - TREE_STATIC(tmp) = 1; - DECL_ARTIFICIAL(tmp) = 1; - if (!TREE_CONSTANT(init)) - make_tmp = fold_build2_loc(loc.gcc_location(), INIT_EXPR, - void_type_node, tmp, init); - else - { - TREE_READONLY(tmp) = 1; - TREE_CONSTANT(tmp) = 1; - DECL_INITIAL(tmp) = init; - make_tmp = NULL_TREE; - } - rest_of_decl_compilation(tmp, 1, 0); - } - - valaddr = build_fold_addr_expr(tmp); - } - - tree descriptor = mt->map_descriptor_pointer(gogo, loc); - - tree type_tree = type_to_tree(this->type_->get_backend(gogo)); - if (type_tree == error_mark_node) - return error_mark_node; - - static tree construct_map_fndecl; - tree call = Gogo::call_builtin(&construct_map_fndecl, - loc, - "__go_construct_map", - 6, - type_tree, - TREE_TYPE(descriptor), - descriptor, - sizetype, - size_int(i), - sizetype, - TYPE_SIZE_UNIT(struct_type), - sizetype, - byte_position(val_field), - sizetype, - TYPE_SIZE_UNIT(TREE_TYPE(val_field)), - const_ptr_type_node, - fold_convert(const_ptr_type_node, valaddr)); - if (call == error_mark_node) - return error_mark_node; - - tree ret; - if (make_tmp == NULL) - ret = call; - else - ret = fold_build2_loc(loc.gcc_location(), COMPOUND_EXPR, type_tree, - make_tmp, call); - return ret; -} - -// Export an array construction. - -void -Map_construction_expression::do_export(Export* exp) const -{ - exp->write_c_string("convert("); - exp->write_type(this->type_); - for (Expression_list::const_iterator pv = this->vals_->begin(); - pv != this->vals_->end(); - ++pv) - { - exp->write_c_string(", "); - (*pv)->export_expression(exp); - } - exp->write_c_string(")"); -} - -// Dump ast representation for a map construction expression. - -void -Map_construction_expression::do_dump_expression( - Ast_dump_context* ast_dump_context) const -{ - ast_dump_context->ostream() << "{" ; - ast_dump_context->dump_expression_list(this->vals_, true); - ast_dump_context->ostream() << "}"; -} - -// A general composite literal. This is lowered to a type specific -// version. - -class Composite_literal_expression : public Parser_expression -{ - public: - Composite_literal_expression(Type* type, int depth, bool has_keys, - Expression_list* vals, Location location) - : Parser_expression(EXPRESSION_COMPOSITE_LITERAL, location), - type_(type), depth_(depth), vals_(vals), has_keys_(has_keys) - { } - - protected: - int - do_traverse(Traverse* traverse); - - Expression* - do_lower(Gogo*, Named_object*, Statement_inserter*, int); - - Expression* - do_copy() - { - return new Composite_literal_expression(this->type_, this->depth_, - this->has_keys_, - (this->vals_ == NULL - ? NULL - : this->vals_->copy()), - this->location()); - } - - void - do_dump_expression(Ast_dump_context*) const; - - private: - Expression* - lower_struct(Gogo*, Type*); - - Expression* - lower_array(Type*); - - Expression* - make_array(Type*, const std::vector<unsigned long>*, Expression_list*); - - Expression* - lower_map(Gogo*, Named_object*, Statement_inserter*, Type*); - - // The type of the composite literal. - Type* type_; - // The depth within a list of composite literals within a composite - // literal, when the type is omitted. - int depth_; - // The values to put in the composite literal. - Expression_list* vals_; - // If this is true, then VALS_ is a list of pairs: a key and a - // value. In an array initializer, a missing key will be NULL. - bool has_keys_; -}; - -// Traversal. - -int -Composite_literal_expression::do_traverse(Traverse* traverse) -{ - if (this->vals_ != NULL - && this->vals_->traverse(traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - return Type::traverse(this->type_, traverse); -} - -// Lower a generic composite literal into a specific version based on -// the type. - -Expression* -Composite_literal_expression::do_lower(Gogo* gogo, Named_object* function, - Statement_inserter* inserter, int) -{ - Type* type = this->type_; - - for (int depth = this->depth_; depth > 0; --depth) - { - if (type->array_type() != NULL) - type = type->array_type()->element_type(); - else if (type->map_type() != NULL) - type = type->map_type()->val_type(); - else - { - if (!type->is_error()) - error_at(this->location(), - ("may only omit types within composite literals " - "of slice, array, or map type")); - return Expression::make_error(this->location()); - } - } - - Type *pt = type->points_to(); - bool is_pointer = false; - if (pt != NULL) - { - is_pointer = true; - type = pt; - } - - Expression* ret; - if (type->is_error()) - return Expression::make_error(this->location()); - else if (type->struct_type() != NULL) - ret = this->lower_struct(gogo, type); - else if (type->array_type() != NULL) - ret = this->lower_array(type); - else if (type->map_type() != NULL) - ret = this->lower_map(gogo, function, inserter, type); - else - { - error_at(this->location(), - ("expected struct, slice, array, or map type " - "for composite literal")); - return Expression::make_error(this->location()); - } - - if (is_pointer) - ret = Expression::make_heap_composite(ret, this->location()); - - return ret; -} - -// Lower a struct composite literal. - -Expression* -Composite_literal_expression::lower_struct(Gogo* gogo, Type* type) -{ - Location location = this->location(); - Struct_type* st = type->struct_type(); - if (this->vals_ == NULL || !this->has_keys_) - { - if (this->vals_ != NULL - && !this->vals_->empty() - && type->named_type() != NULL - && type->named_type()->named_object()->package() != NULL) - { - for (Struct_field_list::const_iterator pf = st->fields()->begin(); - pf != st->fields()->end(); - ++pf) - { - if (Gogo::is_hidden_name(pf->field_name())) - error_at(this->location(), - "assignment of unexported field %qs in %qs literal", - Gogo::message_name(pf->field_name()).c_str(), - type->named_type()->message_name().c_str()); - } - } - - return new Struct_construction_expression(type, this->vals_, location); - } - - size_t field_count = st->field_count(); - std::vector<Expression*> vals(field_count); - std::vector<int>* traverse_order = new(std::vector<int>); - Expression_list::const_iterator p = this->vals_->begin(); - while (p != this->vals_->end()) - { - Expression* name_expr = *p; - - ++p; - go_assert(p != this->vals_->end()); - Expression* val = *p; - - ++p; - - if (name_expr == NULL) - { - error_at(val->location(), "mixture of field and value initializers"); - return Expression::make_error(location); - } - - bool bad_key = false; - std::string name; - const Named_object* no = NULL; - switch (name_expr->classification()) - { - case EXPRESSION_UNKNOWN_REFERENCE: - name = name_expr->unknown_expression()->name(); - break; - - case EXPRESSION_CONST_REFERENCE: - no = static_cast<Const_expression*>(name_expr)->named_object(); - break; - - case EXPRESSION_TYPE: - { - Type* t = name_expr->type(); - Named_type* nt = t->named_type(); - if (nt == NULL) - bad_key = true; - else - no = nt->named_object(); - } - break; - - case EXPRESSION_VAR_REFERENCE: - no = name_expr->var_expression()->named_object(); - break; - - case EXPRESSION_FUNC_REFERENCE: - no = name_expr->func_expression()->named_object(); - break; - - case EXPRESSION_UNARY: - // If there is a local variable around with the same name as - // the field, and this occurs in the closure, then the - // parser may turn the field reference into an indirection - // through the closure. FIXME: This is a mess. - { - bad_key = true; - Unary_expression* ue = static_cast<Unary_expression*>(name_expr); - if (ue->op() == OPERATOR_MULT) - { - Field_reference_expression* fre = - ue->operand()->field_reference_expression(); - if (fre != NULL) - { - Struct_type* st = - fre->expr()->type()->deref()->struct_type(); - if (st != NULL) - { - const Struct_field* sf = st->field(fre->field_index()); - name = sf->field_name(); - - // See below. FIXME. - if (!Gogo::is_hidden_name(name) - && name[0] >= 'a' - && name[0] <= 'z') - { - if (gogo->lookup_global(name.c_str()) != NULL) - name = gogo->pack_hidden_name(name, false); - } - - char buf[20]; - snprintf(buf, sizeof buf, "%u", fre->field_index()); - size_t buflen = strlen(buf); - if (name.compare(name.length() - buflen, buflen, buf) - == 0) - { - name = name.substr(0, name.length() - buflen); - bad_key = false; - } - } - } - } - } - break; - - default: - bad_key = true; - break; - } - if (bad_key) - { - error_at(name_expr->location(), "expected struct field name"); - return Expression::make_error(location); - } - - if (no != NULL) - { - name = no->name(); - - // A predefined name won't be packed. If it starts with a - // lower case letter we need to check for that case, because - // the field name will be packed. FIXME. - if (!Gogo::is_hidden_name(name) - && name[0] >= 'a' - && name[0] <= 'z') - { - Named_object* gno = gogo->lookup_global(name.c_str()); - if (gno == no) - name = gogo->pack_hidden_name(name, false); - } - } - - unsigned int index; - const Struct_field* sf = st->find_local_field(name, &index); - if (sf == NULL) - { - error_at(name_expr->location(), "unknown field %qs in %qs", - Gogo::message_name(name).c_str(), - (type->named_type() != NULL - ? type->named_type()->message_name().c_str() - : "unnamed struct")); - return Expression::make_error(location); - } - if (vals[index] != NULL) - { - error_at(name_expr->location(), - "duplicate value for field %qs in %qs", - Gogo::message_name(name).c_str(), - (type->named_type() != NULL - ? type->named_type()->message_name().c_str() - : "unnamed struct")); - return Expression::make_error(location); - } - - if (type->named_type() != NULL - && type->named_type()->named_object()->package() != NULL - && Gogo::is_hidden_name(sf->field_name())) - error_at(name_expr->location(), - "assignment of unexported field %qs in %qs literal", - Gogo::message_name(sf->field_name()).c_str(), - type->named_type()->message_name().c_str()); - - vals[index] = val; - traverse_order->push_back(index); - } - - Expression_list* list = new Expression_list; - list->reserve(field_count); - for (size_t i = 0; i < field_count; ++i) - list->push_back(vals[i]); - - Struct_construction_expression* ret = - new Struct_construction_expression(type, list, location); - ret->set_traverse_order(traverse_order); - return ret; -} - -// Used to sort an index/value array. - -class Index_value_compare -{ - public: - bool - operator()(const std::pair<unsigned long, Expression*>& a, - const std::pair<unsigned long, Expression*>& b) - { return a.first < b.first; } -}; - -// Lower an array composite literal. - -Expression* -Composite_literal_expression::lower_array(Type* type) -{ - Location location = this->location(); - if (this->vals_ == NULL || !this->has_keys_) - return this->make_array(type, NULL, this->vals_); - - std::vector<unsigned long>* indexes = new std::vector<unsigned long>; - indexes->reserve(this->vals_->size()); - bool indexes_out_of_order = false; - Expression_list* vals = new Expression_list(); - vals->reserve(this->vals_->size()); - unsigned long index = 0; - Expression_list::const_iterator p = this->vals_->begin(); - while (p != this->vals_->end()) - { - Expression* index_expr = *p; - - ++p; - go_assert(p != this->vals_->end()); - Expression* val = *p; - - ++p; - - if (index_expr == NULL) - { - if (!indexes->empty()) - indexes->push_back(index); - } - else - { - if (indexes->empty() && !vals->empty()) - { - for (size_t i = 0; i < vals->size(); ++i) - indexes->push_back(i); - } - - Numeric_constant nc; - if (!index_expr->numeric_constant_value(&nc)) - { - error_at(index_expr->location(), - "index expression is not integer constant"); - return Expression::make_error(location); - } - - switch (nc.to_unsigned_long(&index)) - { - case Numeric_constant::NC_UL_VALID: - break; - case Numeric_constant::NC_UL_NOTINT: - error_at(index_expr->location(), - "index expression is not integer constant"); - return Expression::make_error(location); - case Numeric_constant::NC_UL_NEGATIVE: - error_at(index_expr->location(), "index expression is negative"); - return Expression::make_error(location); - case Numeric_constant::NC_UL_BIG: - error_at(index_expr->location(), "index value overflow"); - return Expression::make_error(location); - default: - go_unreachable(); - } - - Named_type* ntype = Type::lookup_integer_type("int"); - Integer_type* inttype = ntype->integer_type(); - if (sizeof(index) <= static_cast<size_t>(inttype->bits() * 8) - && index >> (inttype->bits() - 1) != 0) - { - error_at(index_expr->location(), "index value overflow"); - return Expression::make_error(location); - } - - if (std::find(indexes->begin(), indexes->end(), index) - != indexes->end()) - { - error_at(index_expr->location(), "duplicate value for index %lu", - index); - return Expression::make_error(location); - } - - if (!indexes->empty() && index < indexes->back()) - indexes_out_of_order = true; - - indexes->push_back(index); - } - - vals->push_back(val); - - ++index; - } - - if (indexes->empty()) - { - delete indexes; - indexes = NULL; - } - - if (indexes_out_of_order) - { - typedef std::vector<std::pair<unsigned long, Expression*> > V; - - V v; - v.reserve(indexes->size()); - std::vector<unsigned long>::const_iterator pi = indexes->begin(); - for (Expression_list::const_iterator pe = vals->begin(); - pe != vals->end(); - ++pe, ++pi) - v.push_back(std::make_pair(*pi, *pe)); - - std::sort(v.begin(), v.end(), Index_value_compare()); - - delete indexes; - delete vals; - indexes = new std::vector<unsigned long>(); - indexes->reserve(v.size()); - vals = new Expression_list(); - vals->reserve(v.size()); - - for (V::const_iterator p = v.begin(); p != v.end(); ++p) - { - indexes->push_back(p->first); - vals->push_back(p->second); - } - } - - return this->make_array(type, indexes, vals); -} - -// Actually build the array composite literal. This handles -// [...]{...}. - -Expression* -Composite_literal_expression::make_array( - Type* type, - const std::vector<unsigned long>* indexes, - Expression_list* vals) -{ - Location location = this->location(); - Array_type* at = type->array_type(); - - if (at->length() != NULL && at->length()->is_nil_expression()) - { - size_t size; - if (vals == NULL) - size = 0; - else if (indexes != NULL) - size = indexes->back() + 1; - else - { - size = vals->size(); - Integer_type* it = Type::lookup_integer_type("int")->integer_type(); - if (sizeof(size) <= static_cast<size_t>(it->bits() * 8) - && size >> (it->bits() - 1) != 0) - { - error_at(location, "too many elements in composite literal"); - return Expression::make_error(location); - } - } - - mpz_t vlen; - mpz_init_set_ui(vlen, size); - Expression* elen = Expression::make_integer(&vlen, NULL, location); - mpz_clear(vlen); - at = Type::make_array_type(at->element_type(), elen); - type = at; - } - else if (at->length() != NULL - && !at->length()->is_error_expression() - && this->vals_ != NULL) - { - Numeric_constant nc; - unsigned long val; - if (at->length()->numeric_constant_value(&nc) - && nc.to_unsigned_long(&val) == Numeric_constant::NC_UL_VALID) - { - if (indexes == NULL) - { - if (this->vals_->size() > val) - { - error_at(location, "too many elements in composite literal"); - return Expression::make_error(location); - } - } - else - { - unsigned long max = indexes->back(); - if (max >= val) - { - error_at(location, - ("some element keys in composite literal " - "are out of range")); - return Expression::make_error(location); - } - } - } - } - - if (at->length() != NULL) - return new Fixed_array_construction_expression(type, indexes, vals, - location); - else - return new Open_array_construction_expression(type, indexes, vals, - location); -} - -// Lower a map composite literal. - -Expression* -Composite_literal_expression::lower_map(Gogo* gogo, Named_object* function, - Statement_inserter* inserter, - Type* type) -{ - Location location = this->location(); - if (this->vals_ != NULL) - { - if (!this->has_keys_) - { - error_at(location, "map composite literal must have keys"); - return Expression::make_error(location); - } - - for (Expression_list::iterator p = this->vals_->begin(); - p != this->vals_->end(); - p += 2) - { - if (*p == NULL) - { - ++p; - error_at((*p)->location(), - "map composite literal must have keys for every value"); - return Expression::make_error(location); - } - // Make sure we have lowered the key; it may not have been - // lowered in order to handle keys for struct composite - // literals. Lower it now to get the right error message. - if ((*p)->unknown_expression() != NULL) - { - (*p)->unknown_expression()->clear_is_composite_literal_key(); - gogo->lower_expression(function, inserter, &*p); - go_assert((*p)->is_error_expression()); - return Expression::make_error(location); - } - } - } - - return new Map_construction_expression(type, this->vals_, location); -} - -// Dump ast representation for a composite literal expression. - -void -Composite_literal_expression::do_dump_expression( - Ast_dump_context* ast_dump_context) const -{ - ast_dump_context->ostream() << "composite("; - ast_dump_context->dump_type(this->type_); - ast_dump_context->ostream() << ", {"; - ast_dump_context->dump_expression_list(this->vals_, this->has_keys_); - ast_dump_context->ostream() << "})"; -} - -// Make a composite literal expression. - -Expression* -Expression::make_composite_literal(Type* type, int depth, bool has_keys, - Expression_list* vals, - Location location) -{ - return new Composite_literal_expression(type, depth, has_keys, vals, - location); -} - -// Return whether this expression is a composite literal. - -bool -Expression::is_composite_literal() const -{ - switch (this->classification_) - { - case EXPRESSION_COMPOSITE_LITERAL: - case EXPRESSION_STRUCT_CONSTRUCTION: - case EXPRESSION_FIXED_ARRAY_CONSTRUCTION: - case EXPRESSION_OPEN_ARRAY_CONSTRUCTION: - case EXPRESSION_MAP_CONSTRUCTION: - return true; - default: - return false; - } -} - -// Return whether this expression is a composite literal which is not -// constant. - -bool -Expression::is_nonconstant_composite_literal() const -{ - switch (this->classification_) - { - case EXPRESSION_STRUCT_CONSTRUCTION: - { - const Struct_construction_expression *psce = - static_cast<const Struct_construction_expression*>(this); - return !psce->is_constant_struct(); - } - case EXPRESSION_FIXED_ARRAY_CONSTRUCTION: - { - const Fixed_array_construction_expression *pace = - static_cast<const Fixed_array_construction_expression*>(this); - return !pace->is_constant_array(); - } - case EXPRESSION_OPEN_ARRAY_CONSTRUCTION: - { - const Open_array_construction_expression *pace = - static_cast<const Open_array_construction_expression*>(this); - return !pace->is_constant_array(); - } - case EXPRESSION_MAP_CONSTRUCTION: - return true; - default: - return false; - } -} - -// Return true if this is a reference to a local variable. - -bool -Expression::is_local_variable() const -{ - const Var_expression* ve = this->var_expression(); - if (ve == NULL) - return false; - const Named_object* no = ve->named_object(); - return (no->is_result_variable() - || (no->is_variable() && !no->var_value()->is_global())); -} - -// Class Type_guard_expression. - -// Traversal. - -int -Type_guard_expression::do_traverse(Traverse* traverse) -{ - if (Expression::traverse(&this->expr_, traverse) == TRAVERSE_EXIT - || Type::traverse(this->type_, traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - return TRAVERSE_CONTINUE; -} - -// Check types of a type guard expression. The expression must have -// an interface type, but the actual type conversion is checked at run -// time. - -void -Type_guard_expression::do_check_types(Gogo*) -{ - Type* expr_type = this->expr_->type(); - if (expr_type->interface_type() == NULL) - { - if (!expr_type->is_error() && !this->type_->is_error()) - this->report_error(_("type assertion only valid for interface types")); - this->set_is_error(); - } - else if (this->type_->interface_type() == NULL) - { - std::string reason; - if (!expr_type->interface_type()->implements_interface(this->type_, - &reason)) - { - if (!this->type_->is_error()) - { - if (reason.empty()) - this->report_error(_("impossible type assertion: " - "type does not implement interface")); - else - error_at(this->location(), - ("impossible type assertion: " - "type does not implement interface (%s)"), - reason.c_str()); - } - this->set_is_error(); - } - } -} - -// Return a tree for a type guard expression. - -tree -Type_guard_expression::do_get_tree(Translate_context* context) -{ - tree expr_tree = this->expr_->get_tree(context); - if (expr_tree == error_mark_node) - return error_mark_node; - if (this->type_->interface_type() != NULL) - return Expression::convert_interface_to_interface(context, this->type_, - this->expr_->type(), - expr_tree, true, - this->location()); - else - return Expression::convert_for_assignment(context, this->type_, - this->expr_->type(), expr_tree, - this->location()); -} - -// Dump ast representation for a type guard expression. - -void -Type_guard_expression::do_dump_expression(Ast_dump_context* ast_dump_context) - const -{ - this->expr_->dump_expression(ast_dump_context); - ast_dump_context->ostream() << "."; - ast_dump_context->dump_type(this->type_); -} - -// Make a type guard expression. - -Expression* -Expression::make_type_guard(Expression* expr, Type* type, - Location location) -{ - return new Type_guard_expression(expr, type, location); -} - -// Class Heap_composite_expression. - -// When you take the address of a composite literal, it is allocated -// on the heap. This class implements that. - -class Heap_composite_expression : public Expression -{ - public: - Heap_composite_expression(Expression* expr, Location location) - : Expression(EXPRESSION_HEAP_COMPOSITE, location), - expr_(expr) - { } - - protected: - int - do_traverse(Traverse* traverse) - { return Expression::traverse(&this->expr_, traverse); } - - Type* - do_type() - { return Type::make_pointer_type(this->expr_->type()); } - - void - do_determine_type(const Type_context*) - { this->expr_->determine_type_no_context(); } - - Expression* - do_copy() - { - return Expression::make_heap_composite(this->expr_->copy(), - this->location()); - } - - tree - do_get_tree(Translate_context*); - - // We only export global objects, and the parser does not generate - // this in global scope. - void - do_export(Export*) const - { go_unreachable(); } - - void - do_dump_expression(Ast_dump_context*) const; - - private: - // The composite literal which is being put on the heap. - Expression* expr_; -}; - -// Return a tree which allocates a composite literal on the heap. - -tree -Heap_composite_expression::do_get_tree(Translate_context* context) -{ - tree expr_tree = this->expr_->get_tree(context); - if (expr_tree == error_mark_node || TREE_TYPE(expr_tree) == error_mark_node) - return error_mark_node; - tree expr_size = TYPE_SIZE_UNIT(TREE_TYPE(expr_tree)); - go_assert(TREE_CODE(expr_size) == INTEGER_CST); - tree space = context->gogo()->allocate_memory(this->expr_->type(), - expr_size, this->location()); - space = fold_convert(build_pointer_type(TREE_TYPE(expr_tree)), space); - space = save_expr(space); - tree ref = build_fold_indirect_ref_loc(this->location().gcc_location(), - space); - TREE_THIS_NOTRAP(ref) = 1; - tree ret = build2(COMPOUND_EXPR, TREE_TYPE(space), - build2(MODIFY_EXPR, void_type_node, ref, expr_tree), - space); - SET_EXPR_LOCATION(ret, this->location().gcc_location()); - return ret; -} - -// Dump ast representation for a heap composite expression. - -void -Heap_composite_expression::do_dump_expression( - Ast_dump_context* ast_dump_context) const -{ - ast_dump_context->ostream() << "&("; - ast_dump_context->dump_expression(this->expr_); - ast_dump_context->ostream() << ")"; -} - -// Allocate a composite literal on the heap. - -Expression* -Expression::make_heap_composite(Expression* expr, Location location) -{ - return new Heap_composite_expression(expr, location); -} - -// Class Receive_expression. - -// Return the type of a receive expression. - -Type* -Receive_expression::do_type() -{ - Channel_type* channel_type = this->channel_->type()->channel_type(); - if (channel_type == NULL) - return Type::make_error_type(); - return channel_type->element_type(); -} - -// Check types for a receive expression. - -void -Receive_expression::do_check_types(Gogo*) -{ - Type* type = this->channel_->type(); - if (type->is_error()) - { - this->set_is_error(); - return; - } - if (type->channel_type() == NULL) - { - this->report_error(_("expected channel")); - return; - } - if (!type->channel_type()->may_receive()) - { - this->report_error(_("invalid receive on send-only channel")); - return; - } -} - -// Get a tree for a receive expression. - -tree -Receive_expression::do_get_tree(Translate_context* context) -{ - Location loc = this->location(); - - Channel_type* channel_type = this->channel_->type()->channel_type(); - if (channel_type == NULL) - { - go_assert(this->channel_->type()->is_error()); - return error_mark_node; - } - - Expression* td = Expression::make_type_descriptor(channel_type, loc); - tree td_tree = td->get_tree(context); - - Type* element_type = channel_type->element_type(); - Btype* element_type_btype = element_type->get_backend(context->gogo()); - tree element_type_tree = type_to_tree(element_type_btype); - - tree channel = this->channel_->get_tree(context); - if (element_type_tree == error_mark_node || channel == error_mark_node) - return error_mark_node; - - return Gogo::receive_from_channel(element_type_tree, td_tree, channel, loc); -} - -// Dump ast representation for a receive expression. - -void -Receive_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const -{ - ast_dump_context->ostream() << " <- " ; - ast_dump_context->dump_expression(channel_); -} - -// Make a receive expression. - -Receive_expression* -Expression::make_receive(Expression* channel, Location location) -{ - return new Receive_expression(channel, location); -} - -// An expression which evaluates to a pointer to the type descriptor -// of a type. - -class Type_descriptor_expression : public Expression -{ - public: - Type_descriptor_expression(Type* type, Location location) - : Expression(EXPRESSION_TYPE_DESCRIPTOR, location), - type_(type) - { } - - protected: - Type* - do_type() - { return Type::make_type_descriptor_ptr_type(); } - - void - do_determine_type(const Type_context*) - { } - - Expression* - do_copy() - { return this; } - - tree - do_get_tree(Translate_context* context) - { - return this->type_->type_descriptor_pointer(context->gogo(), - this->location()); - } - - void - do_dump_expression(Ast_dump_context*) const; - - private: - // The type for which this is the descriptor. - Type* type_; -}; - -// Dump ast representation for a type descriptor expression. - -void -Type_descriptor_expression::do_dump_expression( - Ast_dump_context* ast_dump_context) const -{ - ast_dump_context->dump_type(this->type_); -} - -// Make a type descriptor expression. - -Expression* -Expression::make_type_descriptor(Type* type, Location location) -{ - return new Type_descriptor_expression(type, location); -} - -// An expression which evaluates to some characteristic of a type. -// This is only used to initialize fields of a type descriptor. Using -// a new expression class is slightly inefficient but gives us a good -// separation between the frontend and the middle-end with regard to -// how types are laid out. - -class Type_info_expression : public Expression -{ - public: - Type_info_expression(Type* type, Type_info type_info) - : Expression(EXPRESSION_TYPE_INFO, Linemap::predeclared_location()), - type_(type), type_info_(type_info) - { } - - protected: - Type* - do_type(); - - void - do_determine_type(const Type_context*) - { } - - Expression* - do_copy() - { return this; } - - tree - do_get_tree(Translate_context* context); - - void - do_dump_expression(Ast_dump_context*) const; - - private: - // The type for which we are getting information. - Type* type_; - // What information we want. - Type_info type_info_; -}; - -// The type is chosen to match what the type descriptor struct -// expects. - -Type* -Type_info_expression::do_type() -{ - switch (this->type_info_) - { - case TYPE_INFO_SIZE: - return Type::lookup_integer_type("uintptr"); - case TYPE_INFO_ALIGNMENT: - case TYPE_INFO_FIELD_ALIGNMENT: - return Type::lookup_integer_type("uint8"); - default: - go_unreachable(); - } -} - -// Return type information in GENERIC. - -tree -Type_info_expression::do_get_tree(Translate_context* context) -{ - Btype* btype = this->type_->get_backend(context->gogo()); - Gogo* gogo = context->gogo(); - size_t val; - switch (this->type_info_) - { - case TYPE_INFO_SIZE: - val = gogo->backend()->type_size(btype); - break; - case TYPE_INFO_ALIGNMENT: - val = gogo->backend()->type_alignment(btype); - break; - case TYPE_INFO_FIELD_ALIGNMENT: - val = gogo->backend()->type_field_alignment(btype); - break; - default: - go_unreachable(); - } - tree val_type_tree = type_to_tree(this->type()->get_backend(gogo)); - go_assert(val_type_tree != error_mark_node); - return build_int_cstu(val_type_tree, val); -} - -// Dump ast representation for a type info expression. - -void -Type_info_expression::do_dump_expression( - Ast_dump_context* ast_dump_context) const -{ - ast_dump_context->ostream() << "typeinfo("; - ast_dump_context->dump_type(this->type_); - ast_dump_context->ostream() << ","; - ast_dump_context->ostream() << - (this->type_info_ == TYPE_INFO_ALIGNMENT ? "alignment" - : this->type_info_ == TYPE_INFO_FIELD_ALIGNMENT ? "field alignment" - : this->type_info_ == TYPE_INFO_SIZE ? "size " - : "unknown"); - ast_dump_context->ostream() << ")"; -} - -// Make a type info expression. - -Expression* -Expression::make_type_info(Type* type, Type_info type_info) -{ - return new Type_info_expression(type, type_info); -} - -// An expression which evaluates to the offset of a field within a -// struct. This, like Type_info_expression, q.v., is only used to -// initialize fields of a type descriptor. - -class Struct_field_offset_expression : public Expression -{ - public: - Struct_field_offset_expression(Struct_type* type, const Struct_field* field) - : Expression(EXPRESSION_STRUCT_FIELD_OFFSET, - Linemap::predeclared_location()), - type_(type), field_(field) - { } - - protected: - Type* - do_type() - { return Type::lookup_integer_type("uintptr"); } - - void - do_determine_type(const Type_context*) - { } - - Expression* - do_copy() - { return this; } - - tree - do_get_tree(Translate_context* context); - - void - do_dump_expression(Ast_dump_context*) const; - - private: - // The type of the struct. - Struct_type* type_; - // The field. - const Struct_field* field_; -}; - -// Return a struct field offset in GENERIC. - -tree -Struct_field_offset_expression::do_get_tree(Translate_context* context) -{ - tree type_tree = type_to_tree(this->type_->get_backend(context->gogo())); - if (type_tree == error_mark_node) - return error_mark_node; - - tree val_type_tree = type_to_tree(this->type()->get_backend(context->gogo())); - go_assert(val_type_tree != error_mark_node); - - const Struct_field_list* fields = this->type_->fields(); - tree struct_field_tree = TYPE_FIELDS(type_tree); - Struct_field_list::const_iterator p; - for (p = fields->begin(); - p != fields->end(); - ++p, struct_field_tree = DECL_CHAIN(struct_field_tree)) - { - go_assert(struct_field_tree != NULL_TREE); - if (&*p == this->field_) - break; - } - go_assert(&*p == this->field_); - - return fold_convert_loc(BUILTINS_LOCATION, val_type_tree, - byte_position(struct_field_tree)); -} - -// Dump ast representation for a struct field offset expression. - -void -Struct_field_offset_expression::do_dump_expression( - Ast_dump_context* ast_dump_context) const -{ - ast_dump_context->ostream() << "unsafe.Offsetof("; - ast_dump_context->dump_type(this->type_); - ast_dump_context->ostream() << '.'; - ast_dump_context->ostream() << - Gogo::message_name(this->field_->field_name()); - ast_dump_context->ostream() << ")"; -} - -// Make an expression for a struct field offset. - -Expression* -Expression::make_struct_field_offset(Struct_type* type, - const Struct_field* field) -{ - return new Struct_field_offset_expression(type, field); -} - -// An expression which evaluates to a pointer to the map descriptor of -// a map type. - -class Map_descriptor_expression : public Expression -{ - public: - Map_descriptor_expression(Map_type* type, Location location) - : Expression(EXPRESSION_MAP_DESCRIPTOR, location), - type_(type) - { } - - protected: - Type* - do_type() - { return Type::make_pointer_type(Map_type::make_map_descriptor_type()); } - - void - do_determine_type(const Type_context*) - { } - - Expression* - do_copy() - { return this; } - - tree - do_get_tree(Translate_context* context) - { - return this->type_->map_descriptor_pointer(context->gogo(), - this->location()); - } - - void - do_dump_expression(Ast_dump_context*) const; - - private: - // The type for which this is the descriptor. - Map_type* type_; -}; - -// Dump ast representation for a map descriptor expression. - -void -Map_descriptor_expression::do_dump_expression( - Ast_dump_context* ast_dump_context) const -{ - ast_dump_context->ostream() << "map_descriptor("; - ast_dump_context->dump_type(this->type_); - ast_dump_context->ostream() << ")"; -} - -// Make a map descriptor expression. - -Expression* -Expression::make_map_descriptor(Map_type* type, Location location) -{ - return new Map_descriptor_expression(type, location); -} - -// An expression which evaluates to the address of an unnamed label. - -class Label_addr_expression : public Expression -{ - public: - Label_addr_expression(Label* label, Location location) - : Expression(EXPRESSION_LABEL_ADDR, location), - label_(label) - { } - - protected: - Type* - do_type() - { return Type::make_pointer_type(Type::make_void_type()); } - - void - do_determine_type(const Type_context*) - { } - - Expression* - do_copy() - { return new Label_addr_expression(this->label_, this->location()); } - - tree - do_get_tree(Translate_context* context) - { - return expr_to_tree(this->label_->get_addr(context, this->location())); - } - - void - do_dump_expression(Ast_dump_context* ast_dump_context) const - { ast_dump_context->ostream() << this->label_->name(); } - - private: - // The label whose address we are taking. - Label* label_; -}; - -// Make an expression for the address of an unnamed label. - -Expression* -Expression::make_label_addr(Label* label, Location location) -{ - return new Label_addr_expression(label, location); -} - -// Import an expression. This comes at the end in order to see the -// various class definitions. - -Expression* -Expression::import_expression(Import* imp) -{ - int c = imp->peek_char(); - if (imp->match_c_string("- ") - || imp->match_c_string("! ") - || imp->match_c_string("^ ")) - return Unary_expression::do_import(imp); - else if (c == '(') - return Binary_expression::do_import(imp); - else if (imp->match_c_string("true") - || imp->match_c_string("false")) - return Boolean_expression::do_import(imp); - else if (c == '"') - return String_expression::do_import(imp); - else if (c == '-' || (c >= '0' && c <= '9')) - { - // This handles integers, floats and complex constants. - return Integer_expression::do_import(imp); - } - else if (imp->match_c_string("nil")) - return Nil_expression::do_import(imp); - else if (imp->match_c_string("convert")) - return Type_conversion_expression::do_import(imp); - else - { - error_at(imp->location(), "import error: expected expression"); - return Expression::make_error(imp->location()); - } -} - -// Class Expression_list. - -// Traverse the list. - -int -Expression_list::traverse(Traverse* traverse) -{ - for (Expression_list::iterator p = this->begin(); - p != this->end(); - ++p) - { - if (*p != NULL) - { - if (Expression::traverse(&*p, traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - } - return TRAVERSE_CONTINUE; -} - -// Copy the list. - -Expression_list* -Expression_list::copy() -{ - Expression_list* ret = new Expression_list(); - for (Expression_list::iterator p = this->begin(); - p != this->end(); - ++p) - { - if (*p == NULL) - ret->push_back(NULL); - else - ret->push_back((*p)->copy()); - } - return ret; -} - -// Return whether an expression list has an error expression. - -bool -Expression_list::contains_error() const -{ - for (Expression_list::const_iterator p = this->begin(); - p != this->end(); - ++p) - if (*p != NULL && (*p)->is_error_expression()) - return true; - return false; -} - -// Class Numeric_constant. - -// Destructor. - -Numeric_constant::~Numeric_constant() -{ - this->clear(); -} - -// Copy constructor. - -Numeric_constant::Numeric_constant(const Numeric_constant& a) - : classification_(a.classification_), type_(a.type_) -{ - switch (a.classification_) - { - case NC_INVALID: - break; - case NC_INT: - case NC_RUNE: - mpz_init_set(this->u_.int_val, a.u_.int_val); - break; - case NC_FLOAT: - mpfr_init_set(this->u_.float_val, a.u_.float_val, GMP_RNDN); - break; - case NC_COMPLEX: - mpfr_init_set(this->u_.complex_val.real, a.u_.complex_val.real, - GMP_RNDN); - mpfr_init_set(this->u_.complex_val.imag, a.u_.complex_val.imag, - GMP_RNDN); - break; - default: - go_unreachable(); - } -} - -// Assignment operator. - -Numeric_constant& -Numeric_constant::operator=(const Numeric_constant& a) -{ - this->clear(); - this->classification_ = a.classification_; - this->type_ = a.type_; - switch (a.classification_) - { - case NC_INVALID: - break; - case NC_INT: - case NC_RUNE: - mpz_init_set(this->u_.int_val, a.u_.int_val); - break; - case NC_FLOAT: - mpfr_init_set(this->u_.float_val, a.u_.float_val, GMP_RNDN); - break; - case NC_COMPLEX: - mpfr_init_set(this->u_.complex_val.real, a.u_.complex_val.real, - GMP_RNDN); - mpfr_init_set(this->u_.complex_val.imag, a.u_.complex_val.imag, - GMP_RNDN); - break; - default: - go_unreachable(); - } - return *this; -} - -// Clear the contents. - -void -Numeric_constant::clear() -{ - switch (this->classification_) - { - case NC_INVALID: - break; - case NC_INT: - case NC_RUNE: - mpz_clear(this->u_.int_val); - break; - case NC_FLOAT: - mpfr_clear(this->u_.float_val); - break; - case NC_COMPLEX: - mpfr_clear(this->u_.complex_val.real); - mpfr_clear(this->u_.complex_val.imag); - break; - default: - go_unreachable(); - } - this->classification_ = NC_INVALID; -} - -// Set to an unsigned long value. - -void -Numeric_constant::set_unsigned_long(Type* type, unsigned long val) -{ - this->clear(); - this->classification_ = NC_INT; - this->type_ = type; - mpz_init_set_ui(this->u_.int_val, val); -} - -// Set to an integer value. - -void -Numeric_constant::set_int(Type* type, const mpz_t val) -{ - this->clear(); - this->classification_ = NC_INT; - this->type_ = type; - mpz_init_set(this->u_.int_val, val); -} - -// Set to a rune value. - -void -Numeric_constant::set_rune(Type* type, const mpz_t val) -{ - this->clear(); - this->classification_ = NC_RUNE; - this->type_ = type; - mpz_init_set(this->u_.int_val, val); -} - -// Set to a floating point value. - -void -Numeric_constant::set_float(Type* type, const mpfr_t val) -{ - this->clear(); - this->classification_ = NC_FLOAT; - this->type_ = type; - // Numeric constants do not have negative zero values, so remove - // them here. They also don't have infinity or NaN values, but we - // should never see them here. - if (mpfr_zero_p(val)) - mpfr_init_set_ui(this->u_.float_val, 0, GMP_RNDN); - else - mpfr_init_set(this->u_.float_val, val, GMP_RNDN); -} - -// Set to a complex value. - -void -Numeric_constant::set_complex(Type* type, const mpfr_t real, const mpfr_t imag) -{ - this->clear(); - this->classification_ = NC_COMPLEX; - this->type_ = type; - mpfr_init_set(this->u_.complex_val.real, real, GMP_RNDN); - mpfr_init_set(this->u_.complex_val.imag, imag, GMP_RNDN); -} - -// Get an int value. - -void -Numeric_constant::get_int(mpz_t* val) const -{ - go_assert(this->is_int()); - mpz_init_set(*val, this->u_.int_val); -} - -// Get a rune value. - -void -Numeric_constant::get_rune(mpz_t* val) const -{ - go_assert(this->is_rune()); - mpz_init_set(*val, this->u_.int_val); -} - -// Get a floating point value. - -void -Numeric_constant::get_float(mpfr_t* val) const -{ - go_assert(this->is_float()); - mpfr_init_set(*val, this->u_.float_val, GMP_RNDN); -} - -// Get a complex value. - -void -Numeric_constant::get_complex(mpfr_t* real, mpfr_t* imag) const -{ - go_assert(this->is_complex()); - mpfr_init_set(*real, this->u_.complex_val.real, GMP_RNDN); - mpfr_init_set(*imag, this->u_.complex_val.imag, GMP_RNDN); -} - -// Express value as unsigned long if possible. - -Numeric_constant::To_unsigned_long -Numeric_constant::to_unsigned_long(unsigned long* val) const -{ - switch (this->classification_) - { - case NC_INT: - case NC_RUNE: - return this->mpz_to_unsigned_long(this->u_.int_val, val); - case NC_FLOAT: - return this->mpfr_to_unsigned_long(this->u_.float_val, val); - case NC_COMPLEX: - if (!mpfr_zero_p(this->u_.complex_val.imag)) - return NC_UL_NOTINT; - return this->mpfr_to_unsigned_long(this->u_.complex_val.real, val); - default: - go_unreachable(); - } -} - -// Express integer value as unsigned long if possible. - -Numeric_constant::To_unsigned_long -Numeric_constant::mpz_to_unsigned_long(const mpz_t ival, - unsigned long *val) const -{ - if (mpz_sgn(ival) < 0) - return NC_UL_NEGATIVE; - unsigned long ui = mpz_get_ui(ival); - if (mpz_cmp_ui(ival, ui) != 0) - return NC_UL_BIG; - *val = ui; - return NC_UL_VALID; -} - -// Express floating point value as unsigned long if possible. - -Numeric_constant::To_unsigned_long -Numeric_constant::mpfr_to_unsigned_long(const mpfr_t fval, - unsigned long *val) const -{ - if (!mpfr_integer_p(fval)) - return NC_UL_NOTINT; - mpz_t ival; - mpz_init(ival); - mpfr_get_z(ival, fval, GMP_RNDN); - To_unsigned_long ret = this->mpz_to_unsigned_long(ival, val); - mpz_clear(ival); - return ret; -} - -// Convert value to integer if possible. - -bool -Numeric_constant::to_int(mpz_t* val) const -{ - switch (this->classification_) - { - case NC_INT: - case NC_RUNE: - mpz_init_set(*val, this->u_.int_val); - return true; - case NC_FLOAT: - if (!mpfr_integer_p(this->u_.float_val)) - return false; - mpz_init(*val); - mpfr_get_z(*val, this->u_.float_val, GMP_RNDN); - return true; - case NC_COMPLEX: - if (!mpfr_zero_p(this->u_.complex_val.imag) - || !mpfr_integer_p(this->u_.complex_val.real)) - return false; - mpz_init(*val); - mpfr_get_z(*val, this->u_.complex_val.real, GMP_RNDN); - return true; - default: - go_unreachable(); - } -} - -// Convert value to floating point if possible. - -bool -Numeric_constant::to_float(mpfr_t* val) const -{ - switch (this->classification_) - { - case NC_INT: - case NC_RUNE: - mpfr_init_set_z(*val, this->u_.int_val, GMP_RNDN); - return true; - case NC_FLOAT: - mpfr_init_set(*val, this->u_.float_val, GMP_RNDN); - return true; - case NC_COMPLEX: - if (!mpfr_zero_p(this->u_.complex_val.imag)) - return false; - mpfr_init_set(*val, this->u_.complex_val.real, GMP_RNDN); - return true; - default: - go_unreachable(); - } -} - -// Convert value to complex. - -bool -Numeric_constant::to_complex(mpfr_t* vr, mpfr_t* vi) const -{ - switch (this->classification_) - { - case NC_INT: - case NC_RUNE: - mpfr_init_set_z(*vr, this->u_.int_val, GMP_RNDN); - mpfr_init_set_ui(*vi, 0, GMP_RNDN); - return true; - case NC_FLOAT: - mpfr_init_set(*vr, this->u_.float_val, GMP_RNDN); - mpfr_init_set_ui(*vi, 0, GMP_RNDN); - return true; - case NC_COMPLEX: - mpfr_init_set(*vr, this->u_.complex_val.real, GMP_RNDN); - mpfr_init_set(*vi, this->u_.complex_val.imag, GMP_RNDN); - return true; - default: - go_unreachable(); - } -} - -// Get the type. - -Type* -Numeric_constant::type() const -{ - if (this->type_ != NULL) - return this->type_; - switch (this->classification_) - { - case NC_INT: - return Type::make_abstract_integer_type(); - case NC_RUNE: - return Type::make_abstract_character_type(); - case NC_FLOAT: - return Type::make_abstract_float_type(); - case NC_COMPLEX: - return Type::make_abstract_complex_type(); - default: - go_unreachable(); - } -} - -// If the constant can be expressed in TYPE, then set the type of the -// constant to TYPE and return true. Otherwise return false, and, if -// ISSUE_ERROR is true, report an appropriate error message. - -bool -Numeric_constant::set_type(Type* type, bool issue_error, Location loc) -{ - bool ret; - if (type == NULL) - ret = true; - else if (type->integer_type() != NULL) - ret = this->check_int_type(type->integer_type(), issue_error, loc); - else if (type->float_type() != NULL) - ret = this->check_float_type(type->float_type(), issue_error, loc); - else if (type->complex_type() != NULL) - ret = this->check_complex_type(type->complex_type(), issue_error, loc); - else - go_unreachable(); - if (ret) - this->type_ = type; - return ret; -} - -// Check whether the constant can be expressed in an integer type. - -bool -Numeric_constant::check_int_type(Integer_type* type, bool issue_error, - Location location) const -{ - mpz_t val; - switch (this->classification_) - { - case NC_INT: - case NC_RUNE: - mpz_init_set(val, this->u_.int_val); - break; - - case NC_FLOAT: - if (!mpfr_integer_p(this->u_.float_val)) - { - if (issue_error) - error_at(location, "floating point constant truncated to integer"); - return false; - } - mpz_init(val); - mpfr_get_z(val, this->u_.float_val, GMP_RNDN); - break; - - case NC_COMPLEX: - if (!mpfr_integer_p(this->u_.complex_val.real) - || !mpfr_zero_p(this->u_.complex_val.imag)) - { - if (issue_error) - error_at(location, "complex constant truncated to integer"); - return false; - } - mpz_init(val); - mpfr_get_z(val, this->u_.complex_val.real, GMP_RNDN); - break; - - default: - go_unreachable(); - } - - bool ret; - if (type->is_abstract()) - ret = true; - else - { - int bits = mpz_sizeinbase(val, 2); - if (type->is_unsigned()) - { - // For an unsigned type we can only accept a nonnegative - // number, and we must be able to represents at least BITS. - ret = mpz_sgn(val) >= 0 && bits <= type->bits(); - } - else - { - // For a signed type we need an extra bit to indicate the - // sign. We have to handle the most negative integer - // specially. - ret = (bits + 1 <= type->bits() - || (bits <= type->bits() - && mpz_sgn(val) < 0 - && (mpz_scan1(val, 0) - == static_cast<unsigned long>(type->bits() - 1)) - && mpz_scan0(val, type->bits()) == ULONG_MAX)); - } - } - - if (!ret && issue_error) - error_at(location, "integer constant overflow"); - - return ret; -} - -// Check whether the constant can be expressed in a floating point -// type. - -bool -Numeric_constant::check_float_type(Float_type* type, bool issue_error, - Location location) -{ - mpfr_t val; - switch (this->classification_) - { - case NC_INT: - case NC_RUNE: - mpfr_init_set_z(val, this->u_.int_val, GMP_RNDN); - break; - - case NC_FLOAT: - mpfr_init_set(val, this->u_.float_val, GMP_RNDN); - break; - - case NC_COMPLEX: - if (!mpfr_zero_p(this->u_.complex_val.imag)) - { - if (issue_error) - error_at(location, "complex constant truncated to float"); - return false; - } - mpfr_init_set(val, this->u_.complex_val.real, GMP_RNDN); - break; - - default: - go_unreachable(); - } - - bool ret; - if (type->is_abstract()) - ret = true; - else if (mpfr_nan_p(val) || mpfr_inf_p(val) || mpfr_zero_p(val)) - { - // A NaN or Infinity always fits in the range of the type. - ret = true; - } - else - { - mp_exp_t exp = mpfr_get_exp(val); - mp_exp_t max_exp; - switch (type->bits()) - { - case 32: - max_exp = 128; - break; - case 64: - max_exp = 1024; - break; - default: - go_unreachable(); - } - - ret = exp <= max_exp; - - if (ret) - { - // Round the constant to the desired type. - mpfr_t t; - mpfr_init(t); - switch (type->bits()) - { - case 32: - mpfr_set_prec(t, 24); - break; - case 64: - mpfr_set_prec(t, 53); - break; - default: - go_unreachable(); - } - mpfr_set(t, val, GMP_RNDN); - mpfr_set(val, t, GMP_RNDN); - mpfr_clear(t); - - this->set_float(type, val); - } - } - - mpfr_clear(val); - - if (!ret && issue_error) - error_at(location, "floating point constant overflow"); - - return ret; -} - -// Check whether the constant can be expressed in a complex type. - -bool -Numeric_constant::check_complex_type(Complex_type* type, bool issue_error, - Location location) -{ - if (type->is_abstract()) - return true; - - mp_exp_t max_exp; - switch (type->bits()) - { - case 64: - max_exp = 128; - break; - case 128: - max_exp = 1024; - break; - default: - go_unreachable(); - } - - mpfr_t real; - mpfr_t imag; - switch (this->classification_) - { - case NC_INT: - case NC_RUNE: - mpfr_init_set_z(real, this->u_.int_val, GMP_RNDN); - mpfr_init_set_ui(imag, 0, GMP_RNDN); - break; - - case NC_FLOAT: - mpfr_init_set(real, this->u_.float_val, GMP_RNDN); - mpfr_init_set_ui(imag, 0, GMP_RNDN); - break; - - case NC_COMPLEX: - mpfr_init_set(real, this->u_.complex_val.real, GMP_RNDN); - mpfr_init_set(imag, this->u_.complex_val.imag, GMP_RNDN); - break; - - default: - go_unreachable(); - } - - bool ret = true; - if (!mpfr_nan_p(real) - && !mpfr_inf_p(real) - && !mpfr_zero_p(real) - && mpfr_get_exp(real) > max_exp) - { - if (issue_error) - error_at(location, "complex real part overflow"); - ret = false; - } - - if (!mpfr_nan_p(imag) - && !mpfr_inf_p(imag) - && !mpfr_zero_p(imag) - && mpfr_get_exp(imag) > max_exp) - { - if (issue_error) - error_at(location, "complex imaginary part overflow"); - ret = false; - } - - if (ret) - { - // Round the constant to the desired type. - mpfr_t t; - mpfr_init(t); - switch (type->bits()) - { - case 64: - mpfr_set_prec(t, 24); - break; - case 128: - mpfr_set_prec(t, 53); - break; - default: - go_unreachable(); - } - mpfr_set(t, real, GMP_RNDN); - mpfr_set(real, t, GMP_RNDN); - mpfr_set(t, imag, GMP_RNDN); - mpfr_set(imag, t, GMP_RNDN); - mpfr_clear(t); - - this->set_complex(type, real, imag); - } - - mpfr_clear(real); - mpfr_clear(imag); - - return ret; -} - -// Return an Expression for this value. - -Expression* -Numeric_constant::expression(Location loc) const -{ - switch (this->classification_) - { - case NC_INT: - return Expression::make_integer(&this->u_.int_val, this->type_, loc); - case NC_RUNE: - return Expression::make_character(&this->u_.int_val, this->type_, loc); - case NC_FLOAT: - return Expression::make_float(&this->u_.float_val, this->type_, loc); - case NC_COMPLEX: - return Expression::make_complex(&this->u_.complex_val.real, - &this->u_.complex_val.imag, - this->type_, loc); - default: - go_unreachable(); - } -} diff --git a/gcc-4.8.1/gcc/go/gofrontend/expressions.h b/gcc-4.8.1/gcc/go/gofrontend/expressions.h deleted file mode 100644 index af178de5c..000000000 --- a/gcc-4.8.1/gcc/go/gofrontend/expressions.h +++ /dev/null @@ -1,2268 +0,0 @@ -// expressions.h -- Go frontend expression handling. -*- C++ -*- - -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#ifndef GO_EXPRESSIONS_H -#define GO_EXPRESSIONS_H - -#include <mpfr.h> - -#include "operator.h" - -class Gogo; -class Translate_context; -class Traverse; -class Statement_inserter; -class Type; -struct Type_context; -class Integer_type; -class Float_type; -class Complex_type; -class Function_type; -class Map_type; -class Struct_type; -class Struct_field; -class Expression_list; -class Var_expression; -class Temporary_reference_expression; -class Set_and_use_temporary_expression; -class String_expression; -class Binary_expression; -class Call_expression; -class Func_expression; -class Unknown_expression; -class Index_expression; -class Map_index_expression; -class Bound_method_expression; -class Field_reference_expression; -class Interface_field_reference_expression; -class Type_guard_expression; -class Receive_expression; -class Numeric_constant; -class Named_object; -class Export; -class Import; -class Temporary_statement; -class Label; -class Ast_dump_context; -class String_dump; - -// The base class for all expressions. - -class Expression -{ - public: - // The types of expressions. - enum Expression_classification - { - EXPRESSION_ERROR, - EXPRESSION_TYPE, - EXPRESSION_UNARY, - EXPRESSION_BINARY, - EXPRESSION_CONST_REFERENCE, - EXPRESSION_VAR_REFERENCE, - EXPRESSION_TEMPORARY_REFERENCE, - EXPRESSION_SET_AND_USE_TEMPORARY, - EXPRESSION_SINK, - EXPRESSION_FUNC_REFERENCE, - EXPRESSION_UNKNOWN_REFERENCE, - EXPRESSION_BOOLEAN, - EXPRESSION_STRING, - EXPRESSION_INTEGER, - EXPRESSION_FLOAT, - EXPRESSION_COMPLEX, - EXPRESSION_NIL, - EXPRESSION_IOTA, - EXPRESSION_CALL, - EXPRESSION_CALL_RESULT, - EXPRESSION_BOUND_METHOD, - EXPRESSION_INDEX, - EXPRESSION_ARRAY_INDEX, - EXPRESSION_STRING_INDEX, - EXPRESSION_MAP_INDEX, - EXPRESSION_SELECTOR, - EXPRESSION_FIELD_REFERENCE, - EXPRESSION_INTERFACE_FIELD_REFERENCE, - EXPRESSION_ALLOCATION, - EXPRESSION_TYPE_GUARD, - EXPRESSION_CONVERSION, - EXPRESSION_UNSAFE_CONVERSION, - EXPRESSION_STRUCT_CONSTRUCTION, - EXPRESSION_FIXED_ARRAY_CONSTRUCTION, - EXPRESSION_OPEN_ARRAY_CONSTRUCTION, - EXPRESSION_MAP_CONSTRUCTION, - EXPRESSION_COMPOSITE_LITERAL, - EXPRESSION_HEAP_COMPOSITE, - EXPRESSION_RECEIVE, - EXPRESSION_TYPE_DESCRIPTOR, - EXPRESSION_TYPE_INFO, - EXPRESSION_STRUCT_FIELD_OFFSET, - EXPRESSION_MAP_DESCRIPTOR, - EXPRESSION_LABEL_ADDR - }; - - Expression(Expression_classification, Location); - - virtual ~Expression(); - - // Make an error expression. This is used when a parse error occurs - // to prevent cascading errors. - static Expression* - make_error(Location); - - // Make an expression which is really a type. This is used during - // parsing. - static Expression* - make_type(Type*, Location); - - // Make a unary expression. - static Expression* - make_unary(Operator, Expression*, Location); - - // Make a binary expression. - static Expression* - make_binary(Operator, Expression*, Expression*, Location); - - // Make a reference to a constant in an expression. - static Expression* - make_const_reference(Named_object*, Location); - - // Make a reference to a variable in an expression. - static Expression* - make_var_reference(Named_object*, Location); - - // Make a reference to a temporary variable. Temporary variables - // are always created by a single statement, which is what we use to - // refer to them. - static Temporary_reference_expression* - make_temporary_reference(Temporary_statement*, Location); - - // Make an expressions which sets a temporary variable and then - // evaluates to a reference to that temporary variable. This is - // used to set a temporary variable while retaining the order of - // evaluation. - static Set_and_use_temporary_expression* - make_set_and_use_temporary(Temporary_statement*, Expression*, Location); - - // Make a sink expression--a reference to the blank identifier _. - static Expression* - make_sink(Location); - - // Make a reference to a function in an expression. - static Expression* - make_func_reference(Named_object*, Expression* closure, Location); - - // Make a reference to an unknown name. In a correct program this - // will always be lowered to a real const/var/func reference. - static Unknown_expression* - make_unknown_reference(Named_object*, Location); - - // Make a constant bool expression. - static Expression* - make_boolean(bool val, Location); - - // Make a constant string expression. - static Expression* - make_string(const std::string&, Location); - - // Make a character constant expression. TYPE should be NULL for an - // abstract type. - static Expression* - make_character(const mpz_t*, Type*, Location); - - // Make a constant integer expression. TYPE should be NULL for an - // abstract type. - static Expression* - make_integer(const mpz_t*, Type*, Location); - - // Make a constant float expression. TYPE should be NULL for an - // abstract type. - static Expression* - make_float(const mpfr_t*, Type*, Location); - - // Make a constant complex expression. TYPE should be NULL for an - // abstract type. - static Expression* - make_complex(const mpfr_t* real, const mpfr_t* imag, Type*, Location); - - // Make a nil expression. - static Expression* - make_nil(Location); - - // Make an iota expression. This is used for the predeclared - // constant iota. - static Expression* - make_iota(); - - // Make a call expression. - static Call_expression* - make_call(Expression* func, Expression_list* args, bool is_varargs, - Location); - - // Make a reference to a specific result of a call expression which - // returns a tuple. - static Expression* - make_call_result(Call_expression*, unsigned int index); - - // Make an expression which is a method bound to its first - // parameter. - static Bound_method_expression* - make_bound_method(Expression* object, Named_object* method, Location); - - // Make an index or slice expression. This is a parser expression - // which represents LEFT[START:END]. END may be NULL, meaning an - // index rather than a slice. At parse time we may not know the - // type of LEFT. After parsing this is lowered to an array index, a - // string index, or a map index. - static Expression* - make_index(Expression* left, Expression* start, Expression* end, - Location); - - // Make an array index expression. END may be NULL, in which case - // this is an lvalue. - static Expression* - make_array_index(Expression* array, Expression* start, Expression* end, - Location); - - // Make a string index expression. END may be NULL. This is never - // an lvalue. - static Expression* - make_string_index(Expression* string, Expression* start, Expression* end, - Location); - - // Make a map index expression. This is an lvalue. - static Map_index_expression* - make_map_index(Expression* map, Expression* val, Location); - - // Make a selector. This is a parser expression which represents - // LEFT.NAME. At parse time we may not know the type of the left - // hand side. - static Expression* - make_selector(Expression* left, const std::string& name, Location); - - // Make a reference to a field in a struct. - static Field_reference_expression* - make_field_reference(Expression*, unsigned int field_index, Location); - - // Make a reference to a field of an interface, with an associated - // object. - static Expression* - make_interface_field_reference(Expression*, const std::string&, - Location); - - // Make an allocation expression. - static Expression* - make_allocation(Type*, Location); - - // Make a type guard expression. - static Expression* - make_type_guard(Expression*, Type*, Location); - - // Make a type cast expression. - static Expression* - make_cast(Type*, Expression*, Location); - - // Make an unsafe type cast expression. This is only used when - // passing parameter to builtin functions that are part of the Go - // runtime. - static Expression* - make_unsafe_cast(Type*, Expression*, Location); - - // Make a composite literal. The DEPTH parameter is how far down we - // are in a list of composite literals with omitted types. - static Expression* - make_composite_literal(Type*, int depth, bool has_keys, Expression_list*, - Location); - - // Make a struct composite literal. - static Expression* - make_struct_composite_literal(Type*, Expression_list*, Location); - - // Make a slice composite literal. - static Expression* - make_slice_composite_literal(Type*, Expression_list*, Location); - - // Take a composite literal and allocate it on the heap. - static Expression* - make_heap_composite(Expression*, Location); - - // Make a receive expression. VAL is NULL for a unary receive. - static Receive_expression* - make_receive(Expression* channel, Location); - - // Make an expression which evaluates to the address of the type - // descriptor for TYPE. - static Expression* - make_type_descriptor(Type* type, Location); - - // Make an expression which evaluates to some characteristic of a - // type. These are only used for type descriptors, so there is no - // location parameter. - enum Type_info - { - // The size of a value of the type. - TYPE_INFO_SIZE, - // The required alignment of a value of the type. - TYPE_INFO_ALIGNMENT, - // The required alignment of a value of the type when used as a - // field in a struct. - TYPE_INFO_FIELD_ALIGNMENT - }; - - static Expression* - make_type_info(Type* type, Type_info); - - // Make an expression which evaluates to the offset of a field in a - // struct. This is only used for type descriptors, so there is no - // location parameter. - static Expression* - make_struct_field_offset(Struct_type*, const Struct_field*); - - // Make an expression which evaluates to the address of the map - // descriptor for TYPE. - static Expression* - make_map_descriptor(Map_type* type, Location); - - // Make an expression which evaluates to the address of an unnamed - // label. - static Expression* - make_label_addr(Label*, Location); - - // Return the expression classification. - Expression_classification - classification() const - { return this->classification_; } - - // Return the location of the expression. - Location - location() const - { return this->location_; } - - // Return whether this is a constant expression. - bool - is_constant() const - { return this->do_is_constant(); } - - // If this is not a numeric constant, return false. If it is one, - // return true, and set VAL to hold the value. - bool - numeric_constant_value(Numeric_constant* val) const - { return this->do_numeric_constant_value(val); } - - // If this is not a constant expression with string type, return - // false. If it is one, return true, and set VAL to the value. - bool - string_constant_value(std::string* val) const - { return this->do_string_constant_value(val); } - - // This is called if the value of this expression is being - // discarded. This issues warnings about computed values being - // unused. This returns true if all is well, false if it issued an - // error message. - bool - discarding_value() - { return this->do_discarding_value(); } - - // Return whether this is an error expression. - bool - is_error_expression() const - { return this->classification_ == EXPRESSION_ERROR; } - - // Return whether this expression really represents a type. - bool - is_type_expression() const - { return this->classification_ == EXPRESSION_TYPE; } - - // If this is a variable reference, return the Var_expression - // structure. Otherwise, return NULL. This is a controlled dynamic - // cast. - Var_expression* - var_expression() - { return this->convert<Var_expression, EXPRESSION_VAR_REFERENCE>(); } - - const Var_expression* - var_expression() const - { return this->convert<const Var_expression, EXPRESSION_VAR_REFERENCE>(); } - - // If this is a reference to a temporary variable, return the - // Temporary_reference_expression. Otherwise, return NULL. - Temporary_reference_expression* - temporary_reference_expression() - { - return this->convert<Temporary_reference_expression, - EXPRESSION_TEMPORARY_REFERENCE>(); - } - - // If this is a set-and-use-temporary, return the - // Set_and_use_temporary_expression. Otherwise, return NULL. - Set_and_use_temporary_expression* - set_and_use_temporary_expression() - { - return this->convert<Set_and_use_temporary_expression, - EXPRESSION_SET_AND_USE_TEMPORARY>(); - } - - // Return whether this is a sink expression. - bool - is_sink_expression() const - { return this->classification_ == EXPRESSION_SINK; } - - // If this is a string expression, return the String_expression - // structure. Otherwise, return NULL. - String_expression* - string_expression() - { return this->convert<String_expression, EXPRESSION_STRING>(); } - - // Return whether this is the expression nil. - bool - is_nil_expression() const - { return this->classification_ == EXPRESSION_NIL; } - - // If this is an indirection through a pointer, return the - // expression being pointed through. Otherwise return this. - Expression* - deref(); - - // If this is a binary expression, return the Binary_expression - // structure. Otherwise return NULL. - Binary_expression* - binary_expression() - { return this->convert<Binary_expression, EXPRESSION_BINARY>(); } - - // If this is a call expression, return the Call_expression - // structure. Otherwise, return NULL. This is a controlled dynamic - // cast. - Call_expression* - call_expression() - { return this->convert<Call_expression, EXPRESSION_CALL>(); } - - // If this is an expression which refers to a function, return the - // Func_expression structure. Otherwise, return NULL. - Func_expression* - func_expression() - { return this->convert<Func_expression, EXPRESSION_FUNC_REFERENCE>(); } - - const Func_expression* - func_expression() const - { return this->convert<const Func_expression, EXPRESSION_FUNC_REFERENCE>(); } - - // If this is an expression which refers to an unknown name, return - // the Unknown_expression structure. Otherwise, return NULL. - Unknown_expression* - unknown_expression() - { return this->convert<Unknown_expression, EXPRESSION_UNKNOWN_REFERENCE>(); } - - const Unknown_expression* - unknown_expression() const - { - return this->convert<const Unknown_expression, - EXPRESSION_UNKNOWN_REFERENCE>(); - } - - // If this is an index expression, return the Index_expression - // structure. Otherwise, return NULL. - Index_expression* - index_expression() - { return this->convert<Index_expression, EXPRESSION_INDEX>(); } - - // If this is an expression which refers to indexing in a map, - // return the Map_index_expression structure. Otherwise, return - // NULL. - Map_index_expression* - map_index_expression() - { return this->convert<Map_index_expression, EXPRESSION_MAP_INDEX>(); } - - // If this is a bound method expression, return the - // Bound_method_expression structure. Otherwise, return NULL. - Bound_method_expression* - bound_method_expression() - { return this->convert<Bound_method_expression, EXPRESSION_BOUND_METHOD>(); } - - // If this is a reference to a field in a struct, return the - // Field_reference_expression structure. Otherwise, return NULL. - Field_reference_expression* - field_reference_expression() - { - return this->convert<Field_reference_expression, - EXPRESSION_FIELD_REFERENCE>(); - } - - // If this is a reference to a field in an interface, return the - // Interface_field_reference_expression structure. Otherwise, - // return NULL. - Interface_field_reference_expression* - interface_field_reference_expression() - { - return this->convert<Interface_field_reference_expression, - EXPRESSION_INTERFACE_FIELD_REFERENCE>(); - } - - // If this is a type guard expression, return the - // Type_guard_expression structure. Otherwise, return NULL. - Type_guard_expression* - type_guard_expression() - { return this->convert<Type_guard_expression, EXPRESSION_TYPE_GUARD>(); } - - // If this is a receive expression, return the Receive_expression - // structure. Otherwise, return NULL. - Receive_expression* - receive_expression() - { return this->convert<Receive_expression, EXPRESSION_RECEIVE>(); } - - // Return true if this is a composite literal. - bool - is_composite_literal() const; - - // Return true if this is a composite literal which is not constant. - bool - is_nonconstant_composite_literal() const; - - // Return true if this is a reference to a local variable. - bool - is_local_variable() const; - - // Traverse an expression. - static int - traverse(Expression**, Traverse*); - - // Traverse subexpressions of this expression. - int - traverse_subexpressions(Traverse*); - - // Lower an expression. This is called immediately after parsing. - // FUNCTION is the function we are in; it will be NULL for an - // expression initializing a global variable. INSERTER may be used - // to insert statements before the statement or initializer - // containing this expression; it is normally used to create - // temporary variables. IOTA_VALUE is the value that we should give - // to any iota expressions. This function must resolve expressions - // which could not be fully parsed into their final form. It - // returns the same Expression or a new one. - Expression* - lower(Gogo* gogo, Named_object* function, Statement_inserter* inserter, - int iota_value) - { return this->do_lower(gogo, function, inserter, iota_value); } - - // Determine the real type of an expression with abstract integer, - // floating point, or complex type. TYPE_CONTEXT describes the - // expected type. - void - determine_type(const Type_context*); - - // Check types in an expression. - void - check_types(Gogo* gogo) - { this->do_check_types(gogo); } - - // Determine the type when there is no context. - void - determine_type_no_context(); - - // Return the current type of the expression. This may be changed - // by determine_type. - Type* - type() - { return this->do_type(); } - - // Return a copy of an expression. - Expression* - copy() - { return this->do_copy(); } - - // Return whether the expression is addressable--something which may - // be used as the operand of the unary & operator. - bool - is_addressable() const - { return this->do_is_addressable(); } - - // Note that we are taking the address of this expression. ESCAPES - // is true if this address escapes the current function. - void - address_taken(bool escapes) - { this->do_address_taken(escapes); } - - // Return whether this expression must be evaluated in order - // according to the order of evaluation rules. This is basically - // true of all expressions with side-effects. - bool - must_eval_in_order() const - { return this->do_must_eval_in_order(); } - - // Return whether subexpressions of this expression must be - // evaluated in order. This is true of index expressions and - // pointer indirections. This sets *SKIP to the number of - // subexpressions to skip during traversing, as index expressions - // only requiring moving the index, not the array. - bool - must_eval_subexpressions_in_order(int* skip) const - { - *skip = 0; - return this->do_must_eval_subexpressions_in_order(skip); - } - - // Return the tree for this expression. - tree - get_tree(Translate_context*); - - // Return a tree handling any conversions which must be done during - // assignment. - static tree - convert_for_assignment(Translate_context*, Type* lhs_type, Type* rhs_type, - tree rhs_tree, Location location); - - // Return a tree converting a value of one interface type to another - // interface type. If FOR_TYPE_GUARD is true this is for a type - // assertion. - static tree - convert_interface_to_interface(Translate_context*, Type* lhs_type, - Type* rhs_type, tree rhs_tree, - bool for_type_guard, Location); - - // Return a tree implementing the comparison LHS_TREE OP RHS_TREE. - // TYPE is the type of both sides. - static tree - comparison_tree(Translate_context*, Type* result_type, Operator op, - Type* left_type, tree left_tree, Type* right_type, - tree right_tree, Location); - - // Return a tree for the multi-precision integer VAL in TYPE. - static tree - integer_constant_tree(mpz_t val, tree type); - - // Return a tree for the floating point value VAL in TYPE. - static tree - float_constant_tree(mpfr_t val, tree type); - - // Return a tree for the complex value REAL/IMAG in TYPE. - static tree - complex_constant_tree(mpfr_t real, mpfr_t imag, tree type); - - // Export the expression. This is only used for constants. It will - // be used for things like values of named constants and sizes of - // arrays. - void - export_expression(Export* exp) const - { this->do_export(exp); } - - // Import an expression. - static Expression* - import_expression(Import*); - - // Return a tree which checks that VAL, of arbitrary integer type, - // is non-negative and is not more than the maximum value of - // BOUND_TYPE. If SOFAR is not NULL, it is or'red into the result. - // The return value may be NULL if SOFAR is NULL. - static tree - check_bounds(tree val, tree bound_type, tree sofar, Location); - - // Dump an expression to a dump constext. - void - dump_expression(Ast_dump_context*) const; - - protected: - // May be implemented by child class: traverse the expressions. - virtual int - do_traverse(Traverse*); - - // Return a lowered expression. - virtual Expression* - do_lower(Gogo*, Named_object*, Statement_inserter*, int) - { return this; } - - // Return whether this is a constant expression. - virtual bool - do_is_constant() const - { return false; } - - // Return whether this is a constant expression of numeric type, and - // set the Numeric_constant to the value. - virtual bool - do_numeric_constant_value(Numeric_constant*) const - { return false; } - - // Return whether this is a constant expression of string type, and - // set VAL to the value. - virtual bool - do_string_constant_value(std::string*) const - { return false; } - - // Called by the parser if the value is being discarded. - virtual bool - do_discarding_value(); - - // Child class holds type. - virtual Type* - do_type() = 0; - - // Child class implements determining type information. - virtual void - do_determine_type(const Type_context*) = 0; - - // Child class implements type checking if needed. - virtual void - do_check_types(Gogo*) - { } - - // Child class implements copying. - virtual Expression* - do_copy() = 0; - - // Child class implements whether the expression is addressable. - virtual bool - do_is_addressable() const - { return false; } - - // Child class implements taking the address of an expression. - virtual void - do_address_taken(bool) - { } - - // Child class implements whether this expression must be evaluated - // in order. - virtual bool - do_must_eval_in_order() const - { return false; } - - // Child class implements whether this expressions requires that - // subexpressions be evaluated in order. The child implementation - // may set *SKIP if it should be non-zero. - virtual bool - do_must_eval_subexpressions_in_order(int* /* skip */) const - { return false; } - - // Child class implements conversion to tree. - virtual tree - do_get_tree(Translate_context*) = 0; - - // Child class implements export. - virtual void - do_export(Export*) const; - - // For children to call to give an error for an unused value. - void - unused_value_error(); - - // For children to call when they detect that they are in error. - void - set_is_error(); - - // For children to call to report an error conveniently. - void - report_error(const char*); - - // Child class implements dumping to a dump context. - virtual void - do_dump_expression(Ast_dump_context*) const = 0; - - private: - // Convert to the desired statement classification, or return NULL. - // This is a controlled dynamic cast. - template<typename Expression_class, - Expression_classification expr_classification> - Expression_class* - convert() - { - return (this->classification_ == expr_classification - ? static_cast<Expression_class*>(this) - : NULL); - } - - template<typename Expression_class, - Expression_classification expr_classification> - const Expression_class* - convert() const - { - return (this->classification_ == expr_classification - ? static_cast<const Expression_class*>(this) - : NULL); - } - - static tree - convert_type_to_interface(Translate_context*, Type*, Type*, tree, - Location); - - static tree - get_interface_type_descriptor(Translate_context*, Type*, tree, - Location); - - static tree - convert_interface_to_type(Translate_context*, Type*, Type*, tree, - Location); - - // The expression classification. - Expression_classification classification_; - // The location in the input file. - Location location_; -}; - -// A list of Expressions. - -class Expression_list -{ - public: - Expression_list() - : entries_() - { } - - // Return whether the list is empty. - bool - empty() const - { return this->entries_.empty(); } - - // Return the number of entries in the list. - size_t - size() const - { return this->entries_.size(); } - - // Add an entry to the end of the list. - void - push_back(Expression* expr) - { this->entries_.push_back(expr); } - - void - append(Expression_list* add) - { this->entries_.insert(this->entries_.end(), add->begin(), add->end()); } - - // Reserve space in the list. - void - reserve(size_t size) - { this->entries_.reserve(size); } - - // Traverse the expressions in the list. - int - traverse(Traverse*); - - // Copy the list. - Expression_list* - copy(); - - // Return true if the list contains an error expression. - bool - contains_error() const; - - // Retrieve an element by index. - Expression*& - at(size_t i) - { return this->entries_.at(i); } - - // Return the first and last elements. - Expression*& - front() - { return this->entries_.front(); } - - Expression* - front() const - { return this->entries_.front(); } - - Expression*& - back() - { return this->entries_.back(); } - - Expression* - back() const - { return this->entries_.back(); } - - // Iterators. - - typedef std::vector<Expression*>::iterator iterator; - typedef std::vector<Expression*>::const_iterator const_iterator; - - iterator - begin() - { return this->entries_.begin(); } - - const_iterator - begin() const - { return this->entries_.begin(); } - - iterator - end() - { return this->entries_.end(); } - - const_iterator - end() const - { return this->entries_.end(); } - - // Erase an entry. - void - erase(iterator p) - { this->entries_.erase(p); } - - private: - std::vector<Expression*> entries_; -}; - -// An abstract base class for an expression which is only used by the -// parser, and is lowered in the lowering pass. - -class Parser_expression : public Expression -{ - public: - Parser_expression(Expression_classification classification, - Location location) - : Expression(classification, location) - { } - - protected: - virtual Expression* - do_lower(Gogo*, Named_object*, Statement_inserter*, int) = 0; - - Type* - do_type(); - - void - do_determine_type(const Type_context*) - { go_unreachable(); } - - void - do_check_types(Gogo*) - { go_unreachable(); } - - tree - do_get_tree(Translate_context*) - { go_unreachable(); } -}; - -// An expression which is simply a variable. - -class Var_expression : public Expression -{ - public: - Var_expression(Named_object* variable, Location location) - : Expression(EXPRESSION_VAR_REFERENCE, location), - variable_(variable) - { } - - // Return the variable. - Named_object* - named_object() const - { return this->variable_; } - - protected: - Expression* - do_lower(Gogo*, Named_object*, Statement_inserter*, int); - - Type* - do_type(); - - void - do_determine_type(const Type_context*); - - Expression* - do_copy() - { return this; } - - bool - do_is_addressable() const - { return true; } - - void - do_address_taken(bool); - - tree - do_get_tree(Translate_context*); - - void - do_dump_expression(Ast_dump_context*) const; - - private: - // The variable we are referencing. - Named_object* variable_; -}; - -// A reference to a temporary variable. - -class Temporary_reference_expression : public Expression -{ - public: - Temporary_reference_expression(Temporary_statement* statement, - Location location) - : Expression(EXPRESSION_TEMPORARY_REFERENCE, location), - statement_(statement), is_lvalue_(false) - { } - - // The temporary that this expression refers to. - Temporary_statement* - statement() const - { return this->statement_; } - - // Indicate that this reference appears on the left hand side of an - // assignment statement. - void - set_is_lvalue() - { this->is_lvalue_ = true; } - - protected: - Type* - do_type(); - - void - do_determine_type(const Type_context*) - { } - - Expression* - do_copy() - { return make_temporary_reference(this->statement_, this->location()); } - - bool - do_is_addressable() const - { return true; } - - void - do_address_taken(bool); - - tree - do_get_tree(Translate_context*); - - void - do_dump_expression(Ast_dump_context*) const; - - private: - // The statement where the temporary variable is defined. - Temporary_statement* statement_; - // Whether this reference appears on the left hand side of an - // assignment statement. - bool is_lvalue_; -}; - -// Set and use a temporary variable. - -class Set_and_use_temporary_expression : public Expression -{ - public: - Set_and_use_temporary_expression(Temporary_statement* statement, - Expression* expr, Location location) - : Expression(EXPRESSION_SET_AND_USE_TEMPORARY, location), - statement_(statement), expr_(expr) - { } - - // Return the temporary. - Temporary_statement* - temporary() const - { return this->statement_; } - - // Return the expression. - Expression* - expression() const - { return this->expr_; } - - protected: - int - do_traverse(Traverse* traverse) - { return Expression::traverse(&this->expr_, traverse); } - - Type* - do_type(); - - void - do_determine_type(const Type_context*) - { } - - Expression* - do_copy() - { - return make_set_and_use_temporary(this->statement_, this->expr_, - this->location()); - } - - bool - do_is_addressable() const - { return true; } - - void - do_address_taken(bool); - - tree - do_get_tree(Translate_context*); - - void - do_dump_expression(Ast_dump_context*) const; - - private: - // The statement where the temporary variable is defined. - Temporary_statement* statement_; - // The expression to assign to the temporary. - Expression* expr_; -}; - -// A string expression. - -class String_expression : public Expression -{ - public: - String_expression(const std::string& val, Location location) - : Expression(EXPRESSION_STRING, location), - val_(val), type_(NULL) - { } - - const std::string& - val() const - { return this->val_; } - - static Expression* - do_import(Import*); - - protected: - bool - do_is_constant() const - { return true; } - - bool - do_string_constant_value(std::string* val) const - { - *val = this->val_; - return true; - } - - Type* - do_type(); - - void - do_determine_type(const Type_context*); - - Expression* - do_copy() - { return this; } - - tree - do_get_tree(Translate_context*); - - // Write string literal to a string dump. - static void - export_string(String_dump* exp, const String_expression* str); - - void - do_export(Export*) const; - - void - do_dump_expression(Ast_dump_context*) const; - - private: - // The string value. This is immutable. - const std::string val_; - // The type as determined by context. - Type* type_; -}; - -// A binary expression. - -class Binary_expression : public Expression -{ - public: - Binary_expression(Operator op, Expression* left, Expression* right, - Location location) - : Expression(EXPRESSION_BINARY, location), - op_(op), left_(left), right_(right), type_(NULL) - { } - - // Return the operator. - Operator - op() - { return this->op_; } - - // Return the left hand expression. - Expression* - left() - { return this->left_; } - - // Return the right hand expression. - Expression* - right() - { return this->right_; } - - // Apply binary opcode OP to LEFT_NC and RIGHT_NC, setting NC. - // Return true if this could be done, false if not. Issue errors at - // LOCATION as appropriate. - static bool - eval_constant(Operator op, Numeric_constant* left_nc, - Numeric_constant* right_nc, Location location, - Numeric_constant* nc); - - // Compare constants LEFT_NC and RIGHT_NC according to OP, setting - // *RESULT. Return true if this could be done, false if not. Issue - // errors at LOCATION as appropriate. - static bool - compare_constant(Operator op, Numeric_constant* left_nc, - Numeric_constant* right_nc, Location location, - bool* result); - - static Expression* - do_import(Import*); - - // Report an error if OP can not be applied to TYPE. Return whether - // it can. OTYPE is the type of the other operand. - static bool - check_operator_type(Operator op, Type* type, Type* otype, Location); - - protected: - int - do_traverse(Traverse* traverse); - - Expression* - do_lower(Gogo*, Named_object*, Statement_inserter*, int); - - bool - do_is_constant() const - { return this->left_->is_constant() && this->right_->is_constant(); } - - bool - do_numeric_constant_value(Numeric_constant*) const; - - bool - do_discarding_value(); - - Type* - do_type(); - - void - do_determine_type(const Type_context*); - - void - do_check_types(Gogo*); - - Expression* - do_copy() - { - return Expression::make_binary(this->op_, this->left_->copy(), - this->right_->copy(), this->location()); - } - - tree - do_get_tree(Translate_context*); - - void - do_export(Export*) const; - - void - do_dump_expression(Ast_dump_context*) const; - - private: - static bool - operation_type(Operator op, Type* left_type, Type* right_type, - Type** result_type); - - static bool - cmp_to_bool(Operator op, int cmp); - - static bool - eval_integer(Operator op, const Numeric_constant*, const Numeric_constant*, - Location, Numeric_constant*); - - static bool - eval_float(Operator op, const Numeric_constant*, const Numeric_constant*, - Location, Numeric_constant*); - - static bool - eval_complex(Operator op, const Numeric_constant*, const Numeric_constant*, - Location, Numeric_constant*); - - static bool - compare_integer(const Numeric_constant*, const Numeric_constant*, int*); - - static bool - compare_float(const Numeric_constant*, const Numeric_constant *, int*); - - static bool - compare_complex(const Numeric_constant*, const Numeric_constant*, int*); - - Expression* - lower_struct_comparison(Gogo*, Statement_inserter*); - - Expression* - lower_array_comparison(Gogo*, Statement_inserter*); - - Expression* - lower_compare_to_memcmp(Gogo*, Statement_inserter*); - - Expression* - operand_address(Statement_inserter*, Expression*); - - // The binary operator to apply. - Operator op_; - // The left hand side operand. - Expression* left_; - // The right hand side operand. - Expression* right_; - // The type of a comparison operation. - Type* type_; -}; - -// A call expression. The go statement needs to dig inside this. - -class Call_expression : public Expression -{ - public: - Call_expression(Expression* fn, Expression_list* args, bool is_varargs, - Location location) - : Expression(EXPRESSION_CALL, location), - fn_(fn), args_(args), type_(NULL), results_(NULL), tree_(NULL), - is_varargs_(is_varargs), are_hidden_fields_ok_(false), - varargs_are_lowered_(false), types_are_determined_(false), - is_deferred_(false), issued_error_(false) - { } - - // The function to call. - Expression* - fn() const - { return this->fn_; } - - // The arguments. - Expression_list* - args() - { return this->args_; } - - const Expression_list* - args() const - { return this->args_; } - - // Get the function type. - Function_type* - get_function_type() const; - - // Return the number of values this call will return. - size_t - result_count() const; - - // Return the temporary variable which holds result I. This is only - // valid after the expression has been lowered, and is only valid - // for calls which return multiple results. - Temporary_statement* - result(size_t i) const; - - // Return whether this is a call to the predeclared function - // recover. - bool - is_recover_call() const; - - // Set the argument for a call to recover. - void - set_recover_arg(Expression*); - - // Whether the last argument is a varargs argument (f(a...)). - bool - is_varargs() const - { return this->is_varargs_; } - - // Note that varargs have already been lowered. - void - set_varargs_are_lowered() - { this->varargs_are_lowered_ = true; } - - // Note that it is OK for this call to set hidden fields when - // passing arguments. - void - set_hidden_fields_are_ok() - { this->are_hidden_fields_ok_ = true; } - - // Whether this call is being deferred. - bool - is_deferred() const - { return this->is_deferred_; } - - // Note that the call is being deferred. - void - set_is_deferred() - { this->is_deferred_ = true; } - - // We have found an error with this call expression; return true if - // we should report it. - bool - issue_error(); - - protected: - int - do_traverse(Traverse*); - - virtual Expression* - do_lower(Gogo*, Named_object*, Statement_inserter*, int); - - bool - do_discarding_value() - { return true; } - - virtual Type* - do_type(); - - virtual void - do_determine_type(const Type_context*); - - virtual void - do_check_types(Gogo*); - - Expression* - do_copy() - { - return Expression::make_call(this->fn_->copy(), - (this->args_ == NULL - ? NULL - : this->args_->copy()), - this->is_varargs_, this->location()); - } - - bool - do_must_eval_in_order() const; - - virtual tree - do_get_tree(Translate_context*); - - virtual bool - do_is_recover_call() const; - - virtual void - do_set_recover_arg(Expression*); - - // Let a builtin expression change the argument list. - void - set_args(Expression_list* args) - { this->args_ = args; } - - // Let a builtin expression lower varargs. - void - lower_varargs(Gogo*, Named_object* function, Statement_inserter* inserter, - Type* varargs_type, size_t param_count); - - // Let a builtin expression check whether types have been - // determined. - bool - determining_types(); - - void - do_dump_expression(Ast_dump_context*) const; - - private: - bool - check_argument_type(int, const Type*, const Type*, Location, bool); - - tree - interface_method_function(Translate_context*, - Interface_field_reference_expression*, - tree*); - - tree - set_results(Translate_context*, tree); - - // The function to call. - Expression* fn_; - // The arguments to pass. This may be NULL if there are no - // arguments. - Expression_list* args_; - // The type of the expression, to avoid recomputing it. - Type* type_; - // The list of temporaries which will hold the results if the - // function returns a tuple. - std::vector<Temporary_statement*>* results_; - // The tree for the call, used for a call which returns a tuple. - tree tree_; - // True if the last argument is a varargs argument (f(a...)). - bool is_varargs_; - // True if this statement may pass hidden fields in the arguments. - // This is used for generated method stubs. - bool are_hidden_fields_ok_; - // True if varargs have already been lowered. - bool varargs_are_lowered_; - // True if types have been determined. - bool types_are_determined_; - // True if the call is an argument to a defer statement. - bool is_deferred_; - // True if we reported an error about a mismatch between call - // results and uses. This is to avoid producing multiple errors - // when there are multiple Call_result_expressions. - bool issued_error_; -}; - -// An expression which represents a pointer to a function. - -class Func_expression : public Expression -{ - public: - Func_expression(Named_object* function, Expression* closure, - Location location) - : Expression(EXPRESSION_FUNC_REFERENCE, location), - function_(function), closure_(closure) - { } - - // Return the object associated with the function. - const Named_object* - named_object() const - { return this->function_; } - - // Return the closure for this function. This will return NULL if - // the function has no closure, which is the normal case. - Expression* - closure() - { return this->closure_; } - - // Return a tree for this function without evaluating the closure. - tree - get_tree_without_closure(Gogo*); - - protected: - int - do_traverse(Traverse*); - - Type* - do_type(); - - void - do_determine_type(const Type_context*) - { - if (this->closure_ != NULL) - this->closure_->determine_type_no_context(); - } - - Expression* - do_copy() - { - return Expression::make_func_reference(this->function_, - (this->closure_ == NULL - ? NULL - : this->closure_->copy()), - this->location()); - } - - tree - do_get_tree(Translate_context*); - - void - do_dump_expression(Ast_dump_context*) const; - - private: - // The function itself. - Named_object* function_; - // A closure. This is normally NULL. For a nested function, it may - // be a heap-allocated struct holding pointers to all the variables - // referenced by this function and defined in enclosing functions. - Expression* closure_; -}; - -// A reference to an unknown name. - -class Unknown_expression : public Parser_expression -{ - public: - Unknown_expression(Named_object* named_object, Location location) - : Parser_expression(EXPRESSION_UNKNOWN_REFERENCE, location), - named_object_(named_object), no_error_message_(false), - is_composite_literal_key_(false) - { } - - // The associated named object. - Named_object* - named_object() const - { return this->named_object_; } - - // The name of the identifier which was unknown. - const std::string& - name() const; - - // Call this to indicate that we should not give an error if this - // name is never defined. This is used to avoid knock-on errors - // during an erroneous parse. - void - set_no_error_message() - { this->no_error_message_ = true; } - - // Note that this expression is being used as the key in a composite - // literal, so it may be OK if it is not resolved. - void - set_is_composite_literal_key() - { this->is_composite_literal_key_ = true; } - - // Note that this expression should no longer be treated as a - // composite literal key. - void - clear_is_composite_literal_key() - { this->is_composite_literal_key_ = false; } - - protected: - Expression* - do_lower(Gogo*, Named_object*, Statement_inserter*, int); - - Expression* - do_copy() - { return new Unknown_expression(this->named_object_, this->location()); } - - void - do_dump_expression(Ast_dump_context*) const; - - private: - // The unknown name. - Named_object* named_object_; - // True if we should not give errors if this is undefined. This is - // used if there was a parse failure. - bool no_error_message_; - // True if this is the key in a composite literal. - bool is_composite_literal_key_; -}; - -// An index expression. This is lowered to an array index, a string -// index, or a map index. - -class Index_expression : public Parser_expression -{ - public: - Index_expression(Expression* left, Expression* start, Expression* end, - Location location) - : Parser_expression(EXPRESSION_INDEX, location), - left_(left), start_(start), end_(end), is_lvalue_(false) - { } - - // Record that this expression is an lvalue. - void - set_is_lvalue() - { this->is_lvalue_ = true; } - - // Dump an index expression, i.e. an expression of the form - // expr[expr] or expr[expr:expr], to a dump context. - static void - dump_index_expression(Ast_dump_context*, const Expression* expr, - const Expression* start, const Expression* end); - - protected: - int - do_traverse(Traverse*); - - Expression* - do_lower(Gogo*, Named_object*, Statement_inserter*, int); - - Expression* - do_copy() - { - return new Index_expression(this->left_->copy(), this->start_->copy(), - (this->end_ == NULL - ? NULL - : this->end_->copy()), - this->location()); - } - - bool - do_must_eval_subexpressions_in_order(int* skip) const - { - *skip = 1; - return true; - } - - void - do_dump_expression(Ast_dump_context*) const; - - private: - // The expression being indexed. - Expression* left_; - // The first index. - Expression* start_; - // The second index. This is NULL for an index, non-NULL for a - // slice. - Expression* end_; - // Whether this is being used as an l-value. We set this during the - // parse because map index expressions need to know. - bool is_lvalue_; -}; - -// An index into a map. - -class Map_index_expression : public Expression -{ - public: - Map_index_expression(Expression* map, Expression* index, - Location location) - : Expression(EXPRESSION_MAP_INDEX, location), - map_(map), index_(index), is_lvalue_(false), - is_in_tuple_assignment_(false) - { } - - // Return the map. - Expression* - map() - { return this->map_; } - - const Expression* - map() const - { return this->map_; } - - // Return the index. - Expression* - index() - { return this->index_; } - - const Expression* - index() const - { return this->index_; } - - // Get the type of the map being indexed. - Map_type* - get_map_type() const; - - // Record that this map expression is an lvalue. The difference is - // that an lvalue always inserts the key. - void - set_is_lvalue() - { this->is_lvalue_ = true; } - - // Return whether this map expression occurs in an assignment to a - // pair of values. - bool - is_in_tuple_assignment() const - { return this->is_in_tuple_assignment_; } - - // Record that this map expression occurs in an assignment to a pair - // of values. - void - set_is_in_tuple_assignment() - { this->is_in_tuple_assignment_ = true; } - - // Return a tree for the map index. This returns a tree which - // evaluates to a pointer to a value in the map. If INSERT is true, - // the key will be inserted if not present, and the value pointer - // will be zero initialized. If INSERT is false, and the key is not - // present in the map, the pointer will be NULL. - tree - get_value_pointer(Translate_context*, bool insert); - - protected: - int - do_traverse(Traverse*); - - Type* - do_type(); - - void - do_determine_type(const Type_context*); - - void - do_check_types(Gogo*); - - Expression* - do_copy() - { - return Expression::make_map_index(this->map_->copy(), - this->index_->copy(), - this->location()); - } - - bool - do_must_eval_subexpressions_in_order(int* skip) const - { - *skip = 1; - return true; - } - - // A map index expression is an lvalue but it is not addressable. - - tree - do_get_tree(Translate_context*); - - void - do_dump_expression(Ast_dump_context*) const; - - private: - // The map we are looking into. - Expression* map_; - // The index. - Expression* index_; - // Whether this is an lvalue. - bool is_lvalue_; - // Whether this is in a tuple assignment to a pair of values. - bool is_in_tuple_assignment_; -}; - -// An expression which represents a method bound to its first -// argument. - -class Bound_method_expression : public Expression -{ - public: - Bound_method_expression(Expression* expr, Named_object* method, - Location location) - : Expression(EXPRESSION_BOUND_METHOD, location), - expr_(expr), expr_type_(NULL), method_(method) - { } - - // Return the object which is the first argument. - Expression* - first_argument() - { return this->expr_; } - - // Return the implicit type of the first argument. This will be - // non-NULL when using a method from an anonymous field without - // using an explicit stub. - Type* - first_argument_type() const - { return this->expr_type_; } - - // Return the method function. - Named_object* - method() - { return this->method_; } - - // Set the implicit type of the expression. - void - set_first_argument_type(Type* type) - { this->expr_type_ = type; } - - protected: - int - do_traverse(Traverse*); - - Type* - do_type(); - - void - do_determine_type(const Type_context*); - - void - do_check_types(Gogo*); - - Expression* - do_copy() - { - return new Bound_method_expression(this->expr_->copy(), this->method_, - this->location()); - } - - tree - do_get_tree(Translate_context*); - - void - do_dump_expression(Ast_dump_context*) const; - - private: - // The object used to find the method. This is passed to the method - // as the first argument. - Expression* expr_; - // The implicit type of the object to pass to the method. This is - // NULL in the normal case, non-NULL when using a method from an - // anonymous field which does not require a stub. - Type* expr_type_; - // The method itself. - Named_object* method_; -}; - -// A reference to a field in a struct. - -class Field_reference_expression : public Expression -{ - public: - Field_reference_expression(Expression* expr, unsigned int field_index, - Location location) - : Expression(EXPRESSION_FIELD_REFERENCE, location), - expr_(expr), field_index_(field_index), called_fieldtrack_(false) - { } - - // Return the struct expression. - Expression* - expr() const - { return this->expr_; } - - // Return the field index. - unsigned int - field_index() const - { return this->field_index_; } - - // Set the struct expression. This is used when parsing. - void - set_struct_expression(Expression* expr) - { - go_assert(this->expr_ == NULL); - this->expr_ = expr; - } - - protected: - int - do_traverse(Traverse* traverse) - { return Expression::traverse(&this->expr_, traverse); } - - Expression* - do_lower(Gogo*, Named_object*, Statement_inserter*, int); - - Type* - do_type(); - - void - do_determine_type(const Type_context*) - { this->expr_->determine_type_no_context(); } - - void - do_check_types(Gogo*); - - Expression* - do_copy() - { - return Expression::make_field_reference(this->expr_->copy(), - this->field_index_, - this->location()); - } - - bool - do_is_addressable() const - { return this->expr_->is_addressable(); } - - void - do_address_taken(bool escapes) - { this->expr_->address_taken(escapes); } - - tree - do_get_tree(Translate_context*); - - void - do_dump_expression(Ast_dump_context*) const; - - private: - // The expression we are looking into. This should have a type of - // struct. - Expression* expr_; - // The zero-based index of the field we are retrieving. - unsigned int field_index_; - // Whether we have already emitted a fieldtrack call. - bool called_fieldtrack_; -}; - -// A reference to a field of an interface. - -class Interface_field_reference_expression : public Expression -{ - public: - Interface_field_reference_expression(Expression* expr, - const std::string& name, - Location location) - : Expression(EXPRESSION_INTERFACE_FIELD_REFERENCE, location), - expr_(expr), name_(name) - { } - - // Return the expression for the interface object. - Expression* - expr() - { return this->expr_; } - - // Return the name of the method to call. - const std::string& - name() const - { return this->name_; } - - // Return a tree for the pointer to the function to call, given a - // tree for the expression. - tree - get_function_tree(Translate_context*, tree); - - // Return a tree for the first argument to pass to the interface - // function, given a tree for the expression. This is the real - // object associated with the interface object. - tree - get_underlying_object_tree(Translate_context*, tree); - - protected: - int - do_traverse(Traverse* traverse); - - Type* - do_type(); - - void - do_determine_type(const Type_context*); - - void - do_check_types(Gogo*); - - Expression* - do_copy() - { - return Expression::make_interface_field_reference(this->expr_->copy(), - this->name_, - this->location()); - } - - tree - do_get_tree(Translate_context*); - - void - do_dump_expression(Ast_dump_context*) const; - - private: - // The expression for the interface object. This should have a type - // of interface or pointer to interface. - Expression* expr_; - // The field we are retrieving--the name of the method. - std::string name_; -}; - -// A type guard expression. - -class Type_guard_expression : public Expression -{ - public: - Type_guard_expression(Expression* expr, Type* type, Location location) - : Expression(EXPRESSION_TYPE_GUARD, location), - expr_(expr), type_(type) - { } - - // Return the expression to convert. - Expression* - expr() - { return this->expr_; } - - // Return the type to which to convert. - Type* - type() - { return this->type_; } - - protected: - int - do_traverse(Traverse* traverse); - - Type* - do_type() - { return this->type_; } - - void - do_determine_type(const Type_context*) - { this->expr_->determine_type_no_context(); } - - void - do_check_types(Gogo*); - - Expression* - do_copy() - { - return new Type_guard_expression(this->expr_->copy(), this->type_, - this->location()); - } - - tree - do_get_tree(Translate_context*); - - void - do_dump_expression(Ast_dump_context*) const; - - private: - // The expression to convert. - Expression* expr_; - // The type to which to convert. - Type* type_; -}; - -// A receive expression. - -class Receive_expression : public Expression -{ - public: - Receive_expression(Expression* channel, Location location) - : Expression(EXPRESSION_RECEIVE, location), - channel_(channel) - { } - - // Return the channel. - Expression* - channel() - { return this->channel_; } - - protected: - int - do_traverse(Traverse* traverse) - { return Expression::traverse(&this->channel_, traverse); } - - bool - do_discarding_value() - { return true; } - - Type* - do_type(); - - void - do_determine_type(const Type_context*) - { this->channel_->determine_type_no_context(); } - - void - do_check_types(Gogo*); - - Expression* - do_copy() - { - return Expression::make_receive(this->channel_->copy(), this->location()); - } - - bool - do_must_eval_in_order() const - { return true; } - - tree - do_get_tree(Translate_context*); - - void - do_dump_expression(Ast_dump_context*) const; - - private: - // The channel from which we are receiving. - Expression* channel_; -}; - -// A numeric constant. This is used both for untyped constants and -// for constants that have a type. - -class Numeric_constant -{ - public: - Numeric_constant() - : classification_(NC_INVALID), type_(NULL) - { } - - ~Numeric_constant(); - - Numeric_constant(const Numeric_constant&); - - Numeric_constant& operator=(const Numeric_constant&); - - // Set to an unsigned long value. - void - set_unsigned_long(Type*, unsigned long); - - // Set to an integer value. - void - set_int(Type*, const mpz_t); - - // Set to a rune value. - void - set_rune(Type*, const mpz_t); - - // Set to a floating point value. - void - set_float(Type*, const mpfr_t); - - // Set to a complex value. - void - set_complex(Type*, const mpfr_t, const mpfr_t); - - // Classifiers. - bool - is_int() const - { return this->classification_ == Numeric_constant::NC_INT; } - - bool - is_rune() const - { return this->classification_ == Numeric_constant::NC_RUNE; } - - bool - is_float() const - { return this->classification_ == Numeric_constant::NC_FLOAT; } - - bool - is_complex() const - { return this->classification_ == Numeric_constant::NC_COMPLEX; } - - // Value retrievers. These will initialize the values as well as - // set them. GET_INT is only valid if IS_INT returns true, and - // likewise respectively. - void - get_int(mpz_t*) const; - - void - get_rune(mpz_t*) const; - - void - get_float(mpfr_t*) const; - - void - get_complex(mpfr_t*, mpfr_t*) const; - - // Codes returned by to_unsigned_long. - enum To_unsigned_long - { - // Value is integer and fits in unsigned long. - NC_UL_VALID, - // Value is not integer. - NC_UL_NOTINT, - // Value is integer but is negative. - NC_UL_NEGATIVE, - // Value is non-negative integer but does not fit in unsigned - // long. - NC_UL_BIG - }; - - // If the value can be expressed as an integer that fits in an - // unsigned long, set *VAL and return NC_UL_VALID. Otherwise return - // one of the other To_unsigned_long codes. - To_unsigned_long - to_unsigned_long(unsigned long* val) const; - - // If the value can be expressed as an int, return true and - // initialize and set VAL. This will return false for a value with - // an explicit float or complex type, even if the value is integral. - bool - to_int(mpz_t* val) const; - - // If the value can be expressed as a float, return true and - // initialize and set VAL. - bool - to_float(mpfr_t* val) const; - - // If the value can be expressed as a complex, return true and - // initialize and set VR and VI. - bool - to_complex(mpfr_t* vr, mpfr_t* vi) const; - - // Get the type. - Type* - type() const; - - // If the constant can be expressed in TYPE, then set the type of - // the constant to TYPE and return true. Otherwise return false, - // and, if ISSUE_ERROR is true, issue an error message. LOCATION is - // the location to use for the error. - bool - set_type(Type* type, bool issue_error, Location location); - - // Return an Expression for this value. - Expression* - expression(Location) const; - - private: - void - clear(); - - To_unsigned_long - mpz_to_unsigned_long(const mpz_t ival, unsigned long *val) const; - - To_unsigned_long - mpfr_to_unsigned_long(const mpfr_t fval, unsigned long *val) const; - - bool - check_int_type(Integer_type*, bool, Location) const; - - bool - check_float_type(Float_type*, bool, Location); - - bool - check_complex_type(Complex_type*, bool, Location); - - // The kinds of constants. - enum Classification - { - NC_INVALID, - NC_RUNE, - NC_INT, - NC_FLOAT, - NC_COMPLEX - }; - - // The kind of constant. - Classification classification_; - // The value. - union - { - // If NC_INT or NC_RUNE. - mpz_t int_val; - // If NC_FLOAT. - mpfr_t float_val; - // If NC_COMPLEX. - struct - { - mpfr_t real; - mpfr_t imag; - } complex_val; - } u_; - // The type if there is one. This will be NULL for an untyped - // constant. - Type* type_; -}; - -#endif // !defined(GO_EXPRESSIONS_H) diff --git a/gcc-4.8.1/gcc/go/gofrontend/go-dump.cc b/gcc-4.8.1/gcc/go/gofrontend/go-dump.cc deleted file mode 100644 index dd5a4c3f2..000000000 --- a/gcc-4.8.1/gcc/go/gofrontend/go-dump.cc +++ /dev/null @@ -1,53 +0,0 @@ -// go-dump.cc -- Go frontend debug dumps. - -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "go-system.h" - -#include "go-c.h" -#include "go-dump.h" - -namespace { - -// The list of dumps. - -Go_dump* dumps; - -} // End empty namespace. - -// Create a new dump. - -Go_dump::Go_dump(const char* name) - : next_(dumps), name_(name), is_enabled_(false) -{ - dumps = this; -} - -// Enable a dump by name. - -bool -Go_dump::enable_by_name(const char* name) -{ - bool is_all = strcmp(name, "all") == 0; - bool found = false; - for (Go_dump* p = dumps; p != NULL; p = p->next_) - { - if (is_all || strcmp(name, p->name_) == 0) - { - p->is_enabled_ = true; - found = true; - } - } - return found; -} - -// Enable a dump. Return 1 if this is a real name, 0 if not. - -GO_EXTERN_C -int -go_enable_dump(const char* name) -{ - return Go_dump::enable_by_name(name) ? 1 : 0; -} diff --git a/gcc-4.8.1/gcc/go/gofrontend/go-dump.h b/gcc-4.8.1/gcc/go/gofrontend/go-dump.h deleted file mode 100644 index 13639bc12..000000000 --- a/gcc-4.8.1/gcc/go/gofrontend/go-dump.h +++ /dev/null @@ -1,38 +0,0 @@ -// go-dump.h -- Go frontend debug dumps. -*- C++ -*- - -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#ifndef GO_DUMP_H -#define GO_DUMP_H - -// This class manages different arguments to -fgo-dump-XXX. If you -// want to create a new dump, create a variable of this type with the -// name to use for XXX. You can then use is_enabled to see whether -// the -fgo-dump-XXX option was used on the command line. - -class Go_dump -{ - public: - Go_dump(const char* name); - - // Whether this dump was enabled. - bool - is_enabled() const - { return this->is_enabled_; } - - // Enable a dump by name. Return true if the dump was found. - static bool - enable_by_name(const char*); - - private: - // The next dump. These are not in any order. - Go_dump* next_; - // The name of this dump. - const char* name_; - // Whether this dump was enabled. - bool is_enabled_; -}; - -#endif // !defined(GO_DUMP_H) diff --git a/gcc-4.8.1/gcc/go/gofrontend/go-linemap.h b/gcc-4.8.1/gcc/go/gofrontend/go-linemap.h deleted file mode 100644 index ffbcbe778..000000000 --- a/gcc-4.8.1/gcc/go/gofrontend/go-linemap.h +++ /dev/null @@ -1,131 +0,0 @@ -// go-linemap.h -- interface to location tracking -*- C++ -*- - -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#ifndef GO_LINEMAP_H -#define GO_LINEMAP_H - -#include "go-system.h" - -// The backend must define a type named Location which holds -// information about a location in a source file. The only thing the -// frontend does with instances of Location is pass them back to the -// backend interface. The Location type must be assignable, and it -// must be comparable: i.e., it must support operator= and operator<. -// The type is normally passed by value rather than by reference, and -// it should support that efficiently. The type should be defined in -// "go-location.h". - -#include "go-location.h" - -// The Linemap class is a pure abstract interface, plus some static -// convenience functions. The backend must implement the interface. - -class Linemap -{ - public: - Linemap() - { - // Only one instance of Linemap is allowed to exist. - go_assert(Linemap::instance_ == NULL); - Linemap::instance_ = this; - } - - virtual - ~Linemap() { Linemap::instance_ = NULL; } - - // Subsequent Location values will come from the file named - // FILE_NAME, starting at LINE_BEGIN. Normally LINE_BEGIN will be - // 0, but it will be non-zero if the Go source has a //line comment. - virtual void - start_file(const char* file_name, unsigned int line_begin) = 0; - - // Subsequent Location values will come from the line LINE_NUMBER, - // in the current file. LINE_SIZE is the size of the line in bytes. - // This will normally be called for every line in a source file. - virtual void - start_line(unsigned int line_number, unsigned int line_size) = 0; - - // Get a Location representing column position COLUMN on the current - // line in the current file. - virtual Location - get_location(unsigned int column) = 0; - - // Stop generating Location values. This will be called after all - // input files have been read, in case any cleanup is required. - virtual void - stop() = 0; - - protected: - // Return a special Location used for predeclared identifiers. This - // Location should be different from that for any actual source - // file. This location will be used for various different types, - // functions, and objects created by the frontend. - virtual Location - get_predeclared_location() = 0; - - // Return a special Location which indicates that no actual location - // is known. This is used for undefined objects and for errors. - virtual Location - get_unknown_location() = 0; - - // Return whether the argument is the Location returned by - // get_predeclared_location. - virtual bool - is_predeclared(Location) = 0; - - // Return whether the argument is the Location returned by - // get_unknown_location. - virtual bool - is_unknown(Location) = 0; - - // The single existing instance of Linemap. - static Linemap *instance_; - - public: - // Following are convenience static functions, which allow us to - // access some virtual functions without explicitly passing around - // an instance of Linemap. - - // Return the special Location used for predeclared identifiers. - static Location - predeclared_location() - { - go_assert(Linemap::instance_ != NULL); - return Linemap::instance_->get_predeclared_location(); - } - - // Return the special Location used when no location is known. - static Location - unknown_location() - { - go_assert(Linemap::instance_ != NULL); - return Linemap::instance_->get_unknown_location(); - } - - // Return whether the argument is the special location used for - // predeclared identifiers. - static bool - is_predeclared_location(Location loc) - { - go_assert(Linemap::instance_ != NULL); - return Linemap::instance_->is_predeclared(loc); - } - - // Return whether the argument is the special location used when no - // location is known. - static bool - is_unknown_location(Location loc) - { - go_assert(Linemap::instance_ != NULL); - return Linemap::instance_->is_unknown(loc); - } -}; - -// The backend interface must define this function. It should return -// a fully implemented instance of Linemap. -extern Linemap* go_get_linemap(); - -#endif // !defined(GO_LINEMAP_H) diff --git a/gcc-4.8.1/gcc/go/gofrontend/go-optimize.cc b/gcc-4.8.1/gcc/go/gofrontend/go-optimize.cc deleted file mode 100644 index 6da934f4d..000000000 --- a/gcc-4.8.1/gcc/go/gofrontend/go-optimize.cc +++ /dev/null @@ -1,53 +0,0 @@ -// go-optimize.cc -- Go frontend optimizer flags. - -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "go-system.h" - -#include "go-c.h" -#include "go-optimize.h" - -namespace { - -// The list of optimizations. - -Go_optimize* optimizations; - -} // End empty namespace. - -// Create a new optimization. - -Go_optimize::Go_optimize(const char* name) - : next_(optimizations), name_(name), is_enabled_(false) -{ - optimizations = this; -} - -// Enable an optimization by name. - -bool -Go_optimize::enable_by_name(const char* name) -{ - bool is_all = strcmp(name, "all") == 0; - bool found = false; - for (Go_optimize* p = optimizations; p != NULL; p = p->next_) - { - if (is_all || strcmp(name, p->name_) == 0) - { - p->is_enabled_ = true; - found = true; - } - } - return found; -} - -// Enable an optimization. Return 1 if this is a real name, 0 if not. - -GO_EXTERN_C -int -go_enable_optimize(const char* name) -{ - return Go_optimize::enable_by_name(name) ? 1 : 0; -} diff --git a/gcc-4.8.1/gcc/go/gofrontend/go-optimize.h b/gcc-4.8.1/gcc/go/gofrontend/go-optimize.h deleted file mode 100644 index 8638498e1..000000000 --- a/gcc-4.8.1/gcc/go/gofrontend/go-optimize.h +++ /dev/null @@ -1,38 +0,0 @@ -// go-optimize.h -- Go frontend optimizer flags. -*- C++ -*- - -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#ifndef GO_OPTIMIZE_H -#define GO_OPTIMIZE_H - -// This class manages different arguments to -fgo-optimize-XXX. If you -// want to create a new optimization, create a variable of this type with the -// name to use for XXX. You can then use is_enabled to see whether -// the -fgo-optimize-XXX option was used on the command line. - -class Go_optimize -{ - public: - Go_optimize(const char* name); - - // Whether this optimizaiton was enabled. - bool - is_enabled() const - { return this->is_enabled_; } - - // Enable an optimization by name. Return true if found. - static bool - enable_by_name(const char*); - - private: - // The next optimize flag. These are not in any order. - Go_optimize* next_; - // The name of this optimization pass. - const char* name_; - // Whether this dump was enabled. - bool is_enabled_; -}; - -#endif // !defined(GO_OPTIMIZE_H) diff --git a/gcc-4.8.1/gcc/go/gofrontend/go.cc b/gcc-4.8.1/gcc/go/gofrontend/go.cc deleted file mode 100644 index 11692af80..000000000 --- a/gcc-4.8.1/gcc/go/gofrontend/go.cc +++ /dev/null @@ -1,146 +0,0 @@ -// go.cc -- Go frontend main file for gcc. - -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "go-system.h" - -#include "go-c.h" - -#include "lex.h" -#include "parse.h" -#include "backend.h" -#include "gogo.h" - -// The data structures we build to represent the file. -static Gogo* gogo; - -// Create the main IR data structure. - -GO_EXTERN_C -void -go_create_gogo(int int_type_size, int pointer_size, const char *pkgpath, - const char *prefix, const char *relative_import_path) -{ - go_assert(::gogo == NULL); - Linemap* linemap = go_get_linemap(); - ::gogo = new Gogo(go_get_backend(), linemap, int_type_size, pointer_size); - - if (pkgpath != NULL) - ::gogo->set_pkgpath(pkgpath); - else if (prefix != NULL) - ::gogo->set_prefix(prefix); - - if (relative_import_path != NULL) - ::gogo->set_relative_import_path(relative_import_path); - - // FIXME: This should be in the gcc dependent code. - ::gogo->define_builtin_function_trees(); -} - -// Parse the input files. - -GO_EXTERN_C -void -go_parse_input_files(const char** filenames, unsigned int filename_count, - bool only_check_syntax, bool require_return_statement) -{ - go_assert(filename_count > 0); - - for (unsigned int i = 0; i < filename_count; ++i) - { - if (i > 0) - ::gogo->clear_file_scope(); - - const char* filename = filenames[i]; - FILE* file; - if (strcmp(filename, "-") == 0) - file = stdin; - else - { - file = fopen(filename, "r"); - if (file == NULL) - fatal_error("cannot open %s: %m", filename); - } - - Lex lexer(filename, file, ::gogo->linemap()); - - Parse parse(&lexer, ::gogo); - parse.program(); - - if (strcmp(filename, "-") != 0) - fclose(file); - } - - ::gogo->linemap()->stop(); - - ::gogo->clear_file_scope(); - - // If the global predeclared names are referenced but not defined, - // define them now. - ::gogo->define_global_names(); - - // Finalize method lists and build stub methods for named types. - ::gogo->finalize_methods(); - - // Now that we have seen all the names, lower the parse tree into a - // form which is easier to use. - ::gogo->lower_parse_tree(); - - // Write out queued up functions for hash and comparison of types. - ::gogo->write_specific_type_functions(); - - // Now that we have seen all the names, verify that types are - // correct. - ::gogo->verify_types(); - - // Work out types of unspecified constants and variables. - ::gogo->determine_types(); - - // Check types and issue errors as appropriate. - ::gogo->check_types(); - - if (only_check_syntax) - return; - - // Check that functions have return statements. - if (require_return_statement) - ::gogo->check_return_statements(); - - // Export global identifiers as appropriate. - ::gogo->do_exports(); - - // Turn short-cut operators (&&, ||) into explicit if statements. - ::gogo->remove_shortcuts(); - - // Use temporary variables to force order of evaluation. - ::gogo->order_evaluations(); - - // Build thunks for functions which call recover. - ::gogo->build_recover_thunks(); - - // Convert complicated go and defer statements into simpler ones. - ::gogo->simplify_thunk_statements(); - - // Dump ast, use filename[0] as the base name - ::gogo->dump_ast(filenames[0]); -} - -// Write out globals. - -GO_EXTERN_C -void -go_write_globals() -{ - return ::gogo->write_globals(); -} - -// Return the global IR structure. This is used by some of the -// langhooks to pass to other code. - -Gogo* -go_get_gogo() -{ - return ::gogo; -} diff --git a/gcc-4.8.1/gcc/go/gofrontend/gogo-tree.cc b/gcc-4.8.1/gcc/go/gofrontend/gogo-tree.cc deleted file mode 100644 index b98404519..000000000 --- a/gcc-4.8.1/gcc/go/gofrontend/gogo-tree.cc +++ /dev/null @@ -1,2506 +0,0 @@ -// gogo-tree.cc -- convert Go frontend Gogo IR to gcc trees. - -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "go-system.h" - -#include "toplev.h" -#include "tree.h" -#include "gimple.h" -#include "tree-iterator.h" -#include "cgraph.h" -#include "langhooks.h" -#include "convert.h" -#include "output.h" -#include "diagnostic.h" -#include "go-c.h" - -#include "types.h" -#include "expressions.h" -#include "statements.h" -#include "runtime.h" -#include "backend.h" -#include "gogo.h" - -// Whether we have seen any errors. - -bool -saw_errors() -{ - return errorcount != 0 || sorrycount != 0; -} - -// A helper function. - -static inline tree -get_identifier_from_string(const std::string& str) -{ - return get_identifier_with_length(str.data(), str.length()); -} - -// Builtin functions. - -static std::map<std::string, tree> builtin_functions; - -// Define a builtin function. BCODE is the builtin function code -// defined by builtins.def. NAME is the name of the builtin function. -// LIBNAME is the name of the corresponding library function, and is -// NULL if there isn't one. FNTYPE is the type of the function. -// CONST_P is true if the function has the const attribute. - -static void -define_builtin(built_in_function bcode, const char* name, const char* libname, - tree fntype, bool const_p) -{ - tree decl = add_builtin_function(name, fntype, bcode, BUILT_IN_NORMAL, - libname, NULL_TREE); - if (const_p) - TREE_READONLY(decl) = 1; - set_builtin_decl(bcode, decl, true); - builtin_functions[name] = decl; - if (libname != NULL) - { - decl = add_builtin_function(libname, fntype, bcode, BUILT_IN_NORMAL, - NULL, NULL_TREE); - if (const_p) - TREE_READONLY(decl) = 1; - builtin_functions[libname] = decl; - } -} - -// Create trees for implicit builtin functions. - -void -Gogo::define_builtin_function_trees() -{ - /* We need to define the fetch_and_add functions, since we use them - for ++ and --. */ - tree t = go_type_for_size(BITS_PER_UNIT, 1); - tree p = build_pointer_type(build_qualified_type(t, TYPE_QUAL_VOLATILE)); - define_builtin(BUILT_IN_SYNC_ADD_AND_FETCH_1, "__sync_fetch_and_add_1", NULL, - build_function_type_list(t, p, t, NULL_TREE), false); - - t = go_type_for_size(BITS_PER_UNIT * 2, 1); - p = build_pointer_type(build_qualified_type(t, TYPE_QUAL_VOLATILE)); - define_builtin (BUILT_IN_SYNC_ADD_AND_FETCH_2, "__sync_fetch_and_add_2", NULL, - build_function_type_list(t, p, t, NULL_TREE), false); - - t = go_type_for_size(BITS_PER_UNIT * 4, 1); - p = build_pointer_type(build_qualified_type(t, TYPE_QUAL_VOLATILE)); - define_builtin(BUILT_IN_SYNC_ADD_AND_FETCH_4, "__sync_fetch_and_add_4", NULL, - build_function_type_list(t, p, t, NULL_TREE), false); - - t = go_type_for_size(BITS_PER_UNIT * 8, 1); - p = build_pointer_type(build_qualified_type(t, TYPE_QUAL_VOLATILE)); - define_builtin(BUILT_IN_SYNC_ADD_AND_FETCH_8, "__sync_fetch_and_add_8", NULL, - build_function_type_list(t, p, t, NULL_TREE), false); - - // We use __builtin_expect for magic import functions. - define_builtin(BUILT_IN_EXPECT, "__builtin_expect", NULL, - build_function_type_list(long_integer_type_node, - long_integer_type_node, - long_integer_type_node, - NULL_TREE), - true); - - // We use __builtin_memcmp for struct comparisons. - define_builtin(BUILT_IN_MEMCMP, "__builtin_memcmp", "memcmp", - build_function_type_list(integer_type_node, - const_ptr_type_node, - const_ptr_type_node, - size_type_node, - NULL_TREE), - false); - - // We provide some functions for the math library. - tree math_function_type = build_function_type_list(double_type_node, - double_type_node, - NULL_TREE); - tree math_function_type_long = - build_function_type_list(long_double_type_node, long_double_type_node, - long_double_type_node, NULL_TREE); - tree math_function_type_two = build_function_type_list(double_type_node, - double_type_node, - double_type_node, - NULL_TREE); - tree math_function_type_long_two = - build_function_type_list(long_double_type_node, long_double_type_node, - long_double_type_node, NULL_TREE); - define_builtin(BUILT_IN_ACOS, "__builtin_acos", "acos", - math_function_type, true); - define_builtin(BUILT_IN_ACOSL, "__builtin_acosl", "acosl", - math_function_type_long, true); - define_builtin(BUILT_IN_ASIN, "__builtin_asin", "asin", - math_function_type, true); - define_builtin(BUILT_IN_ASINL, "__builtin_asinl", "asinl", - math_function_type_long, true); - define_builtin(BUILT_IN_ATAN, "__builtin_atan", "atan", - math_function_type, true); - define_builtin(BUILT_IN_ATANL, "__builtin_atanl", "atanl", - math_function_type_long, true); - define_builtin(BUILT_IN_ATAN2, "__builtin_atan2", "atan2", - math_function_type_two, true); - define_builtin(BUILT_IN_ATAN2L, "__builtin_atan2l", "atan2l", - math_function_type_long_two, true); - define_builtin(BUILT_IN_CEIL, "__builtin_ceil", "ceil", - math_function_type, true); - define_builtin(BUILT_IN_CEILL, "__builtin_ceill", "ceill", - math_function_type_long, true); - define_builtin(BUILT_IN_COS, "__builtin_cos", "cos", - math_function_type, true); - define_builtin(BUILT_IN_COSL, "__builtin_cosl", "cosl", - math_function_type_long, true); - define_builtin(BUILT_IN_EXP, "__builtin_exp", "exp", - math_function_type, true); - define_builtin(BUILT_IN_EXPL, "__builtin_expl", "expl", - math_function_type_long, true); - define_builtin(BUILT_IN_EXPM1, "__builtin_expm1", "expm1", - math_function_type, true); - define_builtin(BUILT_IN_EXPM1L, "__builtin_expm1l", "expm1l", - math_function_type_long, true); - define_builtin(BUILT_IN_FABS, "__builtin_fabs", "fabs", - math_function_type, true); - define_builtin(BUILT_IN_FABSL, "__builtin_fabsl", "fabsl", - math_function_type_long, true); - define_builtin(BUILT_IN_FLOOR, "__builtin_floor", "floor", - math_function_type, true); - define_builtin(BUILT_IN_FLOORL, "__builtin_floorl", "floorl", - math_function_type_long, true); - define_builtin(BUILT_IN_FMOD, "__builtin_fmod", "fmod", - math_function_type_two, true); - define_builtin(BUILT_IN_FMODL, "__builtin_fmodl", "fmodl", - math_function_type_long_two, true); - define_builtin(BUILT_IN_LDEXP, "__builtin_ldexp", "ldexp", - build_function_type_list(double_type_node, - double_type_node, - integer_type_node, - NULL_TREE), - true); - define_builtin(BUILT_IN_LDEXPL, "__builtin_ldexpl", "ldexpl", - build_function_type_list(long_double_type_node, - long_double_type_node, - integer_type_node, - NULL_TREE), - true); - define_builtin(BUILT_IN_LOG, "__builtin_log", "log", - math_function_type, true); - define_builtin(BUILT_IN_LOGL, "__builtin_logl", "logl", - math_function_type_long, true); - define_builtin(BUILT_IN_LOG1P, "__builtin_log1p", "log1p", - math_function_type, true); - define_builtin(BUILT_IN_LOG1PL, "__builtin_log1pl", "log1pl", - math_function_type_long, true); - define_builtin(BUILT_IN_LOG10, "__builtin_log10", "log10", - math_function_type, true); - define_builtin(BUILT_IN_LOG10L, "__builtin_log10l", "log10l", - math_function_type_long, true); - define_builtin(BUILT_IN_LOG2, "__builtin_log2", "log2", - math_function_type, true); - define_builtin(BUILT_IN_LOG2L, "__builtin_log2l", "log2l", - math_function_type_long, true); - define_builtin(BUILT_IN_SIN, "__builtin_sin", "sin", - math_function_type, true); - define_builtin(BUILT_IN_SINL, "__builtin_sinl", "sinl", - math_function_type_long, true); - define_builtin(BUILT_IN_SQRT, "__builtin_sqrt", "sqrt", - math_function_type, true); - define_builtin(BUILT_IN_SQRTL, "__builtin_sqrtl", "sqrtl", - math_function_type_long, true); - define_builtin(BUILT_IN_TAN, "__builtin_tan", "tan", - math_function_type, true); - define_builtin(BUILT_IN_TANL, "__builtin_tanl", "tanl", - math_function_type_long, true); - define_builtin(BUILT_IN_TRUNC, "__builtin_trunc", "trunc", - math_function_type, true); - define_builtin(BUILT_IN_TRUNCL, "__builtin_truncl", "truncl", - math_function_type_long, true); - - // We use __builtin_return_address in the thunk we build for - // functions which call recover. - define_builtin(BUILT_IN_RETURN_ADDRESS, "__builtin_return_address", NULL, - build_function_type_list(ptr_type_node, - unsigned_type_node, - NULL_TREE), - false); - - // The compiler uses __builtin_trap for some exception handling - // cases. - define_builtin(BUILT_IN_TRAP, "__builtin_trap", NULL, - build_function_type(void_type_node, void_list_node), - false); -} - -// Get the name to use for the import control function. If there is a -// global function or variable, then we know that that name must be -// unique in the link, and we use it as the basis for our name. - -const std::string& -Gogo::get_init_fn_name() -{ - if (this->init_fn_name_.empty()) - { - go_assert(this->package_ != NULL); - if (this->is_main_package()) - { - // Use a name which the runtime knows. - this->init_fn_name_ = "__go_init_main"; - } - else - { - std::string s = this->pkgpath_symbol(); - s.append("..import"); - this->init_fn_name_ = s; - } - } - - return this->init_fn_name_; -} - -// Add statements to INIT_STMT_LIST which run the initialization -// functions for imported packages. This is only used for the "main" -// package. - -void -Gogo::init_imports(tree* init_stmt_list) -{ - go_assert(this->is_main_package()); - - if (this->imported_init_fns_.empty()) - return; - - tree fntype = build_function_type(void_type_node, void_list_node); - - // We must call them in increasing priority order. - std::vector<Import_init> v; - for (std::set<Import_init>::const_iterator p = - this->imported_init_fns_.begin(); - p != this->imported_init_fns_.end(); - ++p) - v.push_back(*p); - std::sort(v.begin(), v.end()); - - for (std::vector<Import_init>::const_iterator p = v.begin(); - p != v.end(); - ++p) - { - std::string user_name = p->package_name() + ".init"; - tree decl = build_decl(UNKNOWN_LOCATION, FUNCTION_DECL, - get_identifier_from_string(user_name), - fntype); - const std::string& init_name(p->init_name()); - SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(init_name)); - TREE_PUBLIC(decl) = 1; - DECL_EXTERNAL(decl) = 1; - append_to_statement_list(build_call_expr(decl, 0), init_stmt_list); - } -} - -// Register global variables with the garbage collector. We need to -// register all variables which can hold a pointer value. They become -// roots during the mark phase. We build a struct that is easy to -// hook into a list of roots. - -// struct __go_gc_root_list -// { -// struct __go_gc_root_list* __next; -// struct __go_gc_root -// { -// void* __decl; -// size_t __size; -// } __roots[]; -// }; - -// The last entry in the roots array has a NULL decl field. - -void -Gogo::register_gc_vars(const std::vector<Named_object*>& var_gc, - tree* init_stmt_list) -{ - if (var_gc.empty()) - return; - - size_t count = var_gc.size(); - - tree root_type = Gogo::builtin_struct(NULL, "__go_gc_root", NULL_TREE, 2, - "__next", - ptr_type_node, - "__size", - sizetype); - - tree index_type = build_index_type(size_int(count)); - tree array_type = build_array_type(root_type, index_type); - - tree root_list_type = make_node(RECORD_TYPE); - root_list_type = Gogo::builtin_struct(NULL, "__go_gc_root_list", - root_list_type, 2, - "__next", - build_pointer_type(root_list_type), - "__roots", - array_type); - - // Build an initialier for the __roots array. - - vec<constructor_elt, va_gc> *roots_init; - vec_alloc(roots_init, count + 1); - - size_t i = 0; - for (std::vector<Named_object*>::const_iterator p = var_gc.begin(); - p != var_gc.end(); - ++p, ++i) - { - vec<constructor_elt, va_gc> *init; - vec_alloc(init, 2); - - constructor_elt empty = {NULL, NULL}; - constructor_elt* elt = init->quick_push(empty); - tree field = TYPE_FIELDS(root_type); - elt->index = field; - Bvariable* bvar = (*p)->get_backend_variable(this, NULL); - tree decl = var_to_tree(bvar); - go_assert(TREE_CODE(decl) == VAR_DECL); - elt->value = build_fold_addr_expr(decl); - - elt = init->quick_push(empty); - field = DECL_CHAIN(field); - elt->index = field; - elt->value = DECL_SIZE_UNIT(decl); - - elt = roots_init->quick_push(empty); - elt->index = size_int(i); - elt->value = build_constructor(root_type, init); - } - - // The list ends with a NULL entry. - - vec<constructor_elt, va_gc> *init; - vec_alloc(init, 2); - - constructor_elt empty = {NULL, NULL}; - constructor_elt* elt = init->quick_push(empty); - tree field = TYPE_FIELDS(root_type); - elt->index = field; - elt->value = fold_convert(TREE_TYPE(field), null_pointer_node); - - elt = init->quick_push(empty); - field = DECL_CHAIN(field); - elt->index = field; - elt->value = size_zero_node; - - elt = roots_init->quick_push(empty); - elt->index = size_int(i); - elt->value = build_constructor(root_type, init); - - // Build a constructor for the struct. - - vec<constructor_elt, va_gc> *root_list_init; - vec_alloc(root_list_init, 2); - - elt = root_list_init->quick_push(empty); - field = TYPE_FIELDS(root_list_type); - elt->index = field; - elt->value = fold_convert(TREE_TYPE(field), null_pointer_node); - - elt = root_list_init->quick_push(empty); - field = DECL_CHAIN(field); - elt->index = field; - elt->value = build_constructor(array_type, roots_init); - - // Build a decl to register. - - tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL, - create_tmp_var_name("gc"), root_list_type); - DECL_EXTERNAL(decl) = 0; - TREE_PUBLIC(decl) = 0; - TREE_STATIC(decl) = 1; - DECL_ARTIFICIAL(decl) = 1; - DECL_INITIAL(decl) = build_constructor(root_list_type, root_list_init); - rest_of_decl_compilation(decl, 1, 0); - - static tree register_gc_fndecl; - tree call = Gogo::call_builtin(®ister_gc_fndecl, - Linemap::predeclared_location(), - "__go_register_gc_roots", - 1, - void_type_node, - build_pointer_type(root_list_type), - build_fold_addr_expr(decl)); - if (call != error_mark_node) - append_to_statement_list(call, init_stmt_list); -} - -// Build the decl for the initialization function. - -tree -Gogo::initialization_function_decl() -{ - // The tedious details of building your own function. There doesn't - // seem to be a helper function for this. - std::string name = this->package_name() + ".init"; - tree fndecl = build_decl(this->package_->location().gcc_location(), - FUNCTION_DECL, get_identifier_from_string(name), - build_function_type(void_type_node, - void_list_node)); - const std::string& asm_name(this->get_init_fn_name()); - SET_DECL_ASSEMBLER_NAME(fndecl, get_identifier_from_string(asm_name)); - - tree resdecl = build_decl(this->package_->location().gcc_location(), - RESULT_DECL, NULL_TREE, void_type_node); - DECL_ARTIFICIAL(resdecl) = 1; - DECL_CONTEXT(resdecl) = fndecl; - DECL_RESULT(fndecl) = resdecl; - - TREE_STATIC(fndecl) = 1; - TREE_USED(fndecl) = 1; - DECL_ARTIFICIAL(fndecl) = 1; - TREE_PUBLIC(fndecl) = 1; - - DECL_INITIAL(fndecl) = make_node(BLOCK); - TREE_USED(DECL_INITIAL(fndecl)) = 1; - - return fndecl; -} - -// Create the magic initialization function. INIT_STMT_LIST is the -// code that it needs to run. - -void -Gogo::write_initialization_function(tree fndecl, tree init_stmt_list) -{ - // Make sure that we thought we needed an initialization function, - // as otherwise we will not have reported it in the export data. - go_assert(this->is_main_package() || this->need_init_fn_); - - if (fndecl == NULL_TREE) - fndecl = this->initialization_function_decl(); - - DECL_SAVED_TREE(fndecl) = init_stmt_list; - - if (DECL_STRUCT_FUNCTION(fndecl) == NULL) - push_struct_function(fndecl); - else - push_cfun(DECL_STRUCT_FUNCTION(fndecl)); - cfun->function_start_locus = this->package_->location().gcc_location(); - cfun->function_end_locus = cfun->function_start_locus; - - gimplify_function_tree(fndecl); - - cgraph_add_new_function(fndecl, false); - - pop_cfun(); -} - -// Search for references to VAR in any statements or called functions. - -class Find_var : public Traverse -{ - public: - // A hash table we use to avoid looping. The index is the name of a - // named object. We only look through objects defined in this - // package. - typedef Unordered_set(const void*) Seen_objects; - - Find_var(Named_object* var, Seen_objects* seen_objects) - : Traverse(traverse_expressions), - var_(var), seen_objects_(seen_objects), found_(false) - { } - - // Whether the variable was found. - bool - found() const - { return this->found_; } - - int - expression(Expression**); - - private: - // The variable we are looking for. - Named_object* var_; - // Names of objects we have already seen. - Seen_objects* seen_objects_; - // True if the variable was found. - bool found_; -}; - -// See if EXPR refers to VAR, looking through function calls and -// variable initializations. - -int -Find_var::expression(Expression** pexpr) -{ - Expression* e = *pexpr; - - Var_expression* ve = e->var_expression(); - if (ve != NULL) - { - Named_object* v = ve->named_object(); - if (v == this->var_) - { - this->found_ = true; - return TRAVERSE_EXIT; - } - - if (v->is_variable() && v->package() == NULL) - { - Expression* init = v->var_value()->init(); - if (init != NULL) - { - std::pair<Seen_objects::iterator, bool> ins = - this->seen_objects_->insert(v); - if (ins.second) - { - // This is the first time we have seen this name. - if (Expression::traverse(&init, this) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - } - } - } - - // We traverse the code of any function we see. Note that this - // means that we will traverse the code of a function whose address - // is taken even if it is not called. - Func_expression* fe = e->func_expression(); - if (fe != NULL) - { - const Named_object* f = fe->named_object(); - if (f->is_function() && f->package() == NULL) - { - std::pair<Seen_objects::iterator, bool> ins = - this->seen_objects_->insert(f); - if (ins.second) - { - // This is the first time we have seen this name. - if (f->func_value()->block()->traverse(this) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - } - } - - Temporary_reference_expression* tre = e->temporary_reference_expression(); - if (tre != NULL) - { - Temporary_statement* ts = tre->statement(); - Expression* init = ts->init(); - if (init != NULL) - { - std::pair<Seen_objects::iterator, bool> ins = - this->seen_objects_->insert(ts); - if (ins.second) - { - // This is the first time we have seen this temporary - // statement. - if (Expression::traverse(&init, this) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - } - } - - return TRAVERSE_CONTINUE; -} - -// Return true if EXPR, PREINIT, or DEP refers to VAR. - -static bool -expression_requires(Expression* expr, Block* preinit, Named_object* dep, - Named_object* var) -{ - Find_var::Seen_objects seen_objects; - Find_var find_var(var, &seen_objects); - if (expr != NULL) - Expression::traverse(&expr, &find_var); - if (preinit != NULL) - preinit->traverse(&find_var); - if (dep != NULL) - { - Expression* init = dep->var_value()->init(); - if (init != NULL) - Expression::traverse(&init, &find_var); - if (dep->var_value()->has_pre_init()) - dep->var_value()->preinit()->traverse(&find_var); - } - - return find_var.found(); -} - -// Sort variable initializations. If the initialization expression -// for variable A refers directly or indirectly to the initialization -// expression for variable B, then we must initialize B before A. - -class Var_init -{ - public: - Var_init() - : var_(NULL), init_(NULL_TREE) - { } - - Var_init(Named_object* var, tree init) - : var_(var), init_(init) - { } - - // Return the variable. - Named_object* - var() const - { return this->var_; } - - // Return the initialization expression. - tree - init() const - { return this->init_; } - - private: - // The variable being initialized. - Named_object* var_; - // The initialization expression to run. - tree init_; -}; - -typedef std::list<Var_init> Var_inits; - -// Sort the variable initializations. The rule we follow is that we -// emit them in the order they appear in the array, except that if the -// initialization expression for a variable V1 depends upon another -// variable V2 then we initialize V1 after V2. - -static void -sort_var_inits(Gogo* gogo, Var_inits* var_inits) -{ - typedef std::pair<Named_object*, Named_object*> No_no; - typedef std::map<No_no, bool> Cache; - Cache cache; - - Var_inits ready; - while (!var_inits->empty()) - { - Var_inits::iterator p1 = var_inits->begin(); - Named_object* var = p1->var(); - Expression* init = var->var_value()->init(); - Block* preinit = var->var_value()->preinit(); - Named_object* dep = gogo->var_depends_on(var->var_value()); - - // Start walking through the list to see which variables VAR - // needs to wait for. - Var_inits::iterator p2 = p1; - ++p2; - - for (; p2 != var_inits->end(); ++p2) - { - Named_object* p2var = p2->var(); - No_no key(var, p2var); - std::pair<Cache::iterator, bool> ins = - cache.insert(std::make_pair(key, false)); - if (ins.second) - ins.first->second = expression_requires(init, preinit, dep, p2var); - if (ins.first->second) - { - // Check for cycles. - key = std::make_pair(p2var, var); - ins = cache.insert(std::make_pair(key, false)); - if (ins.second) - ins.first->second = - expression_requires(p2var->var_value()->init(), - p2var->var_value()->preinit(), - gogo->var_depends_on(p2var->var_value()), - var); - if (ins.first->second) - { - error_at(var->location(), - ("initialization expressions for %qs and " - "%qs depend upon each other"), - var->message_name().c_str(), - p2var->message_name().c_str()); - inform(p2->var()->location(), "%qs defined here", - p2var->message_name().c_str()); - p2 = var_inits->end(); - } - else - { - // We can't emit P1 until P2 is emitted. Move P1. - Var_inits::iterator p3 = p2; - ++p3; - var_inits->splice(p3, *var_inits, p1); - } - break; - } - } - - if (p2 == var_inits->end()) - { - // VAR does not depends upon any other initialization expressions. - - // Check for a loop of VAR on itself. We only do this if - // INIT is not NULL and there is no dependency; when INIT is - // NULL, it means that PREINIT sets VAR, which we will - // interpret as a loop. - if (init != NULL && dep == NULL - && expression_requires(init, preinit, NULL, var)) - error_at(var->location(), - "initialization expression for %qs depends upon itself", - var->message_name().c_str()); - ready.splice(ready.end(), *var_inits, p1); - } - } - - // Now READY is the list in the desired initialization order. - var_inits->swap(ready); -} - -// Write out the global definitions. - -void -Gogo::write_globals() -{ - this->convert_named_types(); - this->build_interface_method_tables(); - - Bindings* bindings = this->current_bindings(); - size_t count_definitions = bindings->size_definitions(); - size_t count = count_definitions; - - tree* vec = new tree[count]; - - tree init_fndecl = NULL_TREE; - tree init_stmt_list = NULL_TREE; - - if (this->is_main_package()) - this->init_imports(&init_stmt_list); - - // A list of variable initializations. - Var_inits var_inits; - - // A list of variables which need to be registered with the garbage - // collector. - std::vector<Named_object*> var_gc; - var_gc.reserve(count); - - tree var_init_stmt_list = NULL_TREE; - size_t i = 0; - for (Bindings::const_definitions_iterator p = bindings->begin_definitions(); - p != bindings->end_definitions(); - ++p, ++i) - { - Named_object* no = *p; - - go_assert(!no->is_type_declaration() && !no->is_function_declaration()); - // There is nothing to do for a package. - if (no->is_package()) - { - --i; - --count; - continue; - } - - // There is nothing to do for an object which was imported from - // a different package into the global scope. - if (no->package() != NULL) - { - --i; - --count; - continue; - } - - // There is nothing useful we can output for constants which - // have ideal or non-integral type. - if (no->is_const()) - { - Type* type = no->const_value()->type(); - if (type == NULL) - type = no->const_value()->expr()->type(); - if (type->is_abstract() || type->integer_type() == NULL) - { - --i; - --count; - continue; - } - } - - if (!no->is_variable()) - { - vec[i] = no->get_tree(this, NULL); - if (vec[i] == error_mark_node) - { - go_assert(saw_errors()); - --i; - --count; - continue; - } - } - else - { - Bvariable* var = no->get_backend_variable(this, NULL); - vec[i] = var_to_tree(var); - if (vec[i] == error_mark_node) - { - go_assert(saw_errors()); - --i; - --count; - continue; - } - - // Check for a sink variable, which may be used to run an - // initializer purely for its side effects. - bool is_sink = no->name()[0] == '_' && no->name()[1] == '.'; - - tree var_init_tree = NULL_TREE; - if (!no->var_value()->has_pre_init()) - { - tree init = no->var_value()->get_init_tree(this, NULL); - if (init == error_mark_node) - go_assert(saw_errors()); - else if (init == NULL_TREE) - ; - else if (TREE_CONSTANT(init)) - { - if (expression_requires(no->var_value()->init(), NULL, - this->var_depends_on(no->var_value()), - no)) - error_at(no->location(), - "initialization expression for %qs depends " - "upon itself", - no->message_name().c_str()); - this->backend()->global_variable_set_init(var, - tree_to_expr(init)); - } - else if (is_sink - || int_size_in_bytes(TREE_TYPE(init)) == 0 - || int_size_in_bytes(TREE_TYPE(vec[i])) == 0) - var_init_tree = init; - else - var_init_tree = fold_build2_loc(no->location().gcc_location(), - MODIFY_EXPR, void_type_node, - vec[i], init); - } - else - { - // We are going to create temporary variables which - // means that we need an fndecl. - if (init_fndecl == NULL_TREE) - init_fndecl = this->initialization_function_decl(); - if (DECL_STRUCT_FUNCTION(init_fndecl) == NULL) - push_struct_function(init_fndecl); - else - push_cfun(DECL_STRUCT_FUNCTION(init_fndecl)); - tree var_decl = is_sink ? NULL_TREE : vec[i]; - var_init_tree = no->var_value()->get_init_block(this, NULL, - var_decl); - pop_cfun(); - } - - if (var_init_tree != NULL_TREE && var_init_tree != error_mark_node) - { - if (no->var_value()->init() == NULL - && !no->var_value()->has_pre_init()) - append_to_statement_list(var_init_tree, &var_init_stmt_list); - else - var_inits.push_back(Var_init(no, var_init_tree)); - } - else if (this->var_depends_on(no->var_value()) != NULL) - { - // This variable is initialized from something that is - // not in its init or preinit. This variable needs to - // participate in dependency analysis sorting, in case - // some other variable depends on this one. - var_inits.push_back(Var_init(no, integer_zero_node)); - } - - if (!is_sink && no->var_value()->type()->has_pointer()) - var_gc.push_back(no); - } - } - - // Register global variables with the garbage collector. - this->register_gc_vars(var_gc, &init_stmt_list); - - // Simple variable initializations, after all variables are - // registered. - append_to_statement_list(var_init_stmt_list, &init_stmt_list); - - // Complex variable initializations, first sorting them into a - // workable order. - if (!var_inits.empty()) - { - sort_var_inits(this, &var_inits); - for (Var_inits::const_iterator p = var_inits.begin(); - p != var_inits.end(); - ++p) - append_to_statement_list(p->init(), &init_stmt_list); - } - - // After all the variables are initialized, call the "init" - // functions if there are any. - for (std::vector<Named_object*>::const_iterator p = - this->init_functions_.begin(); - p != this->init_functions_.end(); - ++p) - { - tree decl = (*p)->get_tree(this, NULL); - tree call = build_call_expr(decl, 0); - append_to_statement_list(call, &init_stmt_list); - } - - // Set up a magic function to do all the initialization actions. - // This will be called if this package is imported. - if (init_stmt_list != NULL_TREE - || this->need_init_fn_ - || this->is_main_package()) - this->write_initialization_function(init_fndecl, init_stmt_list); - - // We should not have seen any new bindings created during the - // conversion. - go_assert(count_definitions == this->current_bindings()->size_definitions()); - - // Pass everything back to the middle-end. - - wrapup_global_declarations(vec, count); - - finalize_compilation_unit(); - - check_global_declarations(vec, count); - emit_debug_global_declarations(vec, count); - - delete[] vec; -} - -// Get a tree for the identifier for a named object. - -tree -Named_object::get_id(Gogo* gogo) -{ - go_assert(!this->is_variable() && !this->is_result_variable()); - std::string decl_name; - if (this->is_function_declaration() - && !this->func_declaration_value()->asm_name().empty()) - decl_name = this->func_declaration_value()->asm_name(); - else if (this->is_type() - && Linemap::is_predeclared_location(this->type_value()->location())) - { - // We don't need the package name for builtin types. - decl_name = Gogo::unpack_hidden_name(this->name_); - } - else - { - std::string package_name; - if (this->package_ == NULL) - package_name = gogo->package_name(); - else - package_name = this->package_->package_name(); - - decl_name = package_name + '.' + Gogo::unpack_hidden_name(this->name_); - - Function_type* fntype; - if (this->is_function()) - fntype = this->func_value()->type(); - else if (this->is_function_declaration()) - fntype = this->func_declaration_value()->type(); - else - fntype = NULL; - if (fntype != NULL && fntype->is_method()) - { - decl_name.push_back('.'); - decl_name.append(fntype->receiver()->type()->mangled_name(gogo)); - } - } - if (this->is_type()) - { - unsigned int index; - const Named_object* in_function = this->type_value()->in_function(&index); - if (in_function != NULL) - { - decl_name += '$' + Gogo::unpack_hidden_name(in_function->name()); - if (index > 0) - { - char buf[30]; - snprintf(buf, sizeof buf, "%u", index); - decl_name += '$'; - decl_name += buf; - } - } - } - return get_identifier_from_string(decl_name); -} - -// Get a tree for a named object. - -tree -Named_object::get_tree(Gogo* gogo, Named_object* function) -{ - if (this->tree_ != NULL_TREE) - return this->tree_; - - tree name; - if (this->classification_ == NAMED_OBJECT_TYPE) - name = NULL_TREE; - else - name = this->get_id(gogo); - tree decl; - switch (this->classification_) - { - case NAMED_OBJECT_CONST: - { - Named_constant* named_constant = this->u_.const_value; - Translate_context subcontext(gogo, function, NULL, NULL); - tree expr_tree = named_constant->expr()->get_tree(&subcontext); - if (expr_tree == error_mark_node) - decl = error_mark_node; - else - { - Type* type = named_constant->type(); - if (type != NULL && !type->is_abstract()) - { - if (type->is_error()) - expr_tree = error_mark_node; - else - { - Btype* btype = type->get_backend(gogo); - expr_tree = fold_convert(type_to_tree(btype), expr_tree); - } - } - if (expr_tree == error_mark_node) - decl = error_mark_node; - else if (INTEGRAL_TYPE_P(TREE_TYPE(expr_tree))) - { - decl = build_decl(named_constant->location().gcc_location(), - CONST_DECL, name, TREE_TYPE(expr_tree)); - DECL_INITIAL(decl) = expr_tree; - TREE_CONSTANT(decl) = 1; - TREE_READONLY(decl) = 1; - } - else - { - // A CONST_DECL is only for an enum constant, so we - // shouldn't use for non-integral types. Instead we - // just return the constant itself, rather than a - // decl. - decl = expr_tree; - } - } - } - break; - - case NAMED_OBJECT_TYPE: - { - Named_type* named_type = this->u_.type_value; - tree type_tree = type_to_tree(named_type->get_backend(gogo)); - if (type_tree == error_mark_node) - decl = error_mark_node; - else - { - decl = TYPE_NAME(type_tree); - go_assert(decl != NULL_TREE); - - // We need to produce a type descriptor for every named - // type, and for a pointer to every named type, since - // other files or packages might refer to them. We need - // to do this even for hidden types, because they might - // still be returned by some function. Simply calling the - // type_descriptor method is enough to create the type - // descriptor, even though we don't do anything with it. - if (this->package_ == NULL) - { - named_type-> - type_descriptor_pointer(gogo, - Linemap::predeclared_location()); - Type* pn = Type::make_pointer_type(named_type); - pn->type_descriptor_pointer(gogo, - Linemap::predeclared_location()); - } - } - } - break; - - case NAMED_OBJECT_TYPE_DECLARATION: - error("reference to undefined type %qs", - this->message_name().c_str()); - return error_mark_node; - - case NAMED_OBJECT_VAR: - case NAMED_OBJECT_RESULT_VAR: - case NAMED_OBJECT_SINK: - go_unreachable(); - - case NAMED_OBJECT_FUNC: - { - Function* func = this->u_.func_value; - decl = func->get_or_make_decl(gogo, this, name); - if (decl != error_mark_node) - { - if (func->block() != NULL) - { - if (DECL_STRUCT_FUNCTION(decl) == NULL) - push_struct_function(decl); - else - push_cfun(DECL_STRUCT_FUNCTION(decl)); - - cfun->function_start_locus = func->location().gcc_location(); - cfun->function_end_locus = - func->block()->end_location().gcc_location(); - - func->build_tree(gogo, this); - - gimplify_function_tree(decl); - - cgraph_finalize_function(decl, true); - - pop_cfun(); - } - } - } - break; - - case NAMED_OBJECT_ERRONEOUS: - decl = error_mark_node; - break; - - default: - go_unreachable(); - } - - if (TREE_TYPE(decl) == error_mark_node) - decl = error_mark_node; - - tree ret = decl; - - this->tree_ = ret; - - if (ret != error_mark_node) - go_preserve_from_gc(ret); - - return ret; -} - -// Get the initial value of a variable as a tree. This does not -// consider whether the variable is in the heap--it returns the -// initial value as though it were always stored in the stack. - -tree -Variable::get_init_tree(Gogo* gogo, Named_object* function) -{ - go_assert(this->preinit_ == NULL); - if (this->init_ == NULL) - { - go_assert(!this->is_parameter_); - if (this->is_global_ || this->is_in_heap()) - return NULL; - Btype* btype = this->type_->get_backend(gogo); - return expr_to_tree(gogo->backend()->zero_expression(btype)); - } - else - { - Translate_context context(gogo, function, NULL, NULL); - tree rhs_tree = this->init_->get_tree(&context); - return Expression::convert_for_assignment(&context, this->type(), - this->init_->type(), - rhs_tree, this->location()); - } -} - -// Get the initial value of a variable when a block is required. -// VAR_DECL is the decl to set; it may be NULL for a sink variable. - -tree -Variable::get_init_block(Gogo* gogo, Named_object* function, tree var_decl) -{ - go_assert(this->preinit_ != NULL); - - // We want to add the variable assignment to the end of the preinit - // block. The preinit block may have a TRY_FINALLY_EXPR and a - // TRY_CATCH_EXPR; if it does, we want to add to the end of the - // regular statements. - - Translate_context context(gogo, function, NULL, NULL); - Bblock* bblock = this->preinit_->get_backend(&context); - tree block_tree = block_to_tree(bblock); - if (block_tree == error_mark_node) - return error_mark_node; - go_assert(TREE_CODE(block_tree) == BIND_EXPR); - tree statements = BIND_EXPR_BODY(block_tree); - while (statements != NULL_TREE - && (TREE_CODE(statements) == TRY_FINALLY_EXPR - || TREE_CODE(statements) == TRY_CATCH_EXPR)) - statements = TREE_OPERAND(statements, 0); - - // It's possible to have pre-init statements without an initializer - // if the pre-init statements set the variable. - if (this->init_ != NULL) - { - tree rhs_tree = this->init_->get_tree(&context); - if (rhs_tree == error_mark_node) - return error_mark_node; - if (var_decl == NULL_TREE) - append_to_statement_list(rhs_tree, &statements); - else - { - tree val = Expression::convert_for_assignment(&context, this->type(), - this->init_->type(), - rhs_tree, - this->location()); - if (val == error_mark_node) - return error_mark_node; - tree set = fold_build2_loc(this->location().gcc_location(), - MODIFY_EXPR, void_type_node, var_decl, - val); - append_to_statement_list(set, &statements); - } - } - - return block_tree; -} - -// Get a tree for a function decl. - -tree -Function::get_or_make_decl(Gogo* gogo, Named_object* no, tree id) -{ - if (this->fndecl_ == NULL_TREE) - { - tree functype = type_to_tree(this->type_->get_backend(gogo)); - if (functype == error_mark_node) - this->fndecl_ = error_mark_node; - else - { - // The type of a function comes back as a pointer, but we - // want the real function type for a function declaration. - go_assert(POINTER_TYPE_P(functype)); - functype = TREE_TYPE(functype); - tree decl = build_decl(this->location().gcc_location(), FUNCTION_DECL, - id, functype); - - this->fndecl_ = decl; - - if (no->package() != NULL) - ; - else if (this->enclosing_ != NULL || Gogo::is_thunk(no)) - ; - else if (Gogo::unpack_hidden_name(no->name()) == "init" - && !this->type_->is_method()) - ; - else if (Gogo::unpack_hidden_name(no->name()) == "main" - && gogo->is_main_package()) - TREE_PUBLIC(decl) = 1; - // Methods have to be public even if they are hidden because - // they can be pulled into type descriptors when using - // anonymous fields. - else if (!Gogo::is_hidden_name(no->name()) - || this->type_->is_method()) - { - TREE_PUBLIC(decl) = 1; - std::string asm_name = gogo->pkgpath_symbol(); - asm_name.append(1, '.'); - asm_name.append(Gogo::unpack_hidden_name(no->name())); - if (this->type_->is_method()) - { - asm_name.append(1, '.'); - Type* rtype = this->type_->receiver()->type(); - asm_name.append(rtype->mangled_name(gogo)); - } - SET_DECL_ASSEMBLER_NAME(decl, - get_identifier_from_string(asm_name)); - } - - // Why do we have to do this in the frontend? - tree restype = TREE_TYPE(functype); - tree resdecl = - build_decl(this->location().gcc_location(), RESULT_DECL, NULL_TREE, - restype); - DECL_ARTIFICIAL(resdecl) = 1; - DECL_IGNORED_P(resdecl) = 1; - DECL_CONTEXT(resdecl) = decl; - DECL_RESULT(decl) = resdecl; - - if (this->enclosing_ != NULL) - DECL_STATIC_CHAIN(decl) = 1; - - // If a function calls the predeclared recover function, we - // can't inline it, because recover behaves differently in a - // function passed directly to defer. If this is a recover - // thunk that we built to test whether a function can be - // recovered, we can't inline it, because that will mess up - // our return address comparison. - if (this->calls_recover_ || this->is_recover_thunk_) - DECL_UNINLINABLE(decl) = 1; - - // If this is a thunk created to call a function which calls - // the predeclared recover function, we need to disable - // stack splitting for the thunk. - if (this->is_recover_thunk_) - { - tree attr = get_identifier("__no_split_stack__"); - DECL_ATTRIBUTES(decl) = tree_cons(attr, NULL_TREE, NULL_TREE); - } - - if (this->in_unique_section_) - resolve_unique_section (decl, 0, 1); - - go_preserve_from_gc(decl); - - if (this->closure_var_ != NULL) - { - push_struct_function(decl); - - Bvariable* bvar = this->closure_var_->get_backend_variable(gogo, - no); - tree closure_decl = var_to_tree(bvar); - if (closure_decl == error_mark_node) - this->fndecl_ = error_mark_node; - else - { - DECL_ARTIFICIAL(closure_decl) = 1; - DECL_IGNORED_P(closure_decl) = 1; - TREE_USED(closure_decl) = 1; - DECL_ARG_TYPE(closure_decl) = TREE_TYPE(closure_decl); - TREE_READONLY(closure_decl) = 1; - - DECL_STRUCT_FUNCTION(decl)->static_chain_decl = closure_decl; - } - - pop_cfun(); - } - } - } - return this->fndecl_; -} - -// Get a tree for a function declaration. - -tree -Function_declaration::get_or_make_decl(Gogo* gogo, Named_object* no, tree id) -{ - if (this->fndecl_ == NULL_TREE) - { - // Let Go code use an asm declaration to pick up a builtin - // function. - if (!this->asm_name_.empty()) - { - std::map<std::string, tree>::const_iterator p = - builtin_functions.find(this->asm_name_); - if (p != builtin_functions.end()) - { - this->fndecl_ = p->second; - return this->fndecl_; - } - } - - tree functype = type_to_tree(this->fntype_->get_backend(gogo)); - tree decl; - if (functype == error_mark_node) - decl = error_mark_node; - else - { - // The type of a function comes back as a pointer, but we - // want the real function type for a function declaration. - go_assert(POINTER_TYPE_P(functype)); - functype = TREE_TYPE(functype); - decl = build_decl(this->location().gcc_location(), FUNCTION_DECL, id, - functype); - TREE_PUBLIC(decl) = 1; - DECL_EXTERNAL(decl) = 1; - - if (this->asm_name_.empty()) - { - std::string asm_name = (no->package() == NULL - ? gogo->pkgpath_symbol() - : no->package()->pkgpath_symbol()); - asm_name.append(1, '.'); - asm_name.append(Gogo::unpack_hidden_name(no->name())); - if (this->fntype_->is_method()) - { - asm_name.append(1, '.'); - Type* rtype = this->fntype_->receiver()->type(); - asm_name.append(rtype->mangled_name(gogo)); - } - SET_DECL_ASSEMBLER_NAME(decl, - get_identifier_from_string(asm_name)); - } - } - this->fndecl_ = decl; - go_preserve_from_gc(decl); - } - return this->fndecl_; -} - -// We always pass the receiver to a method as a pointer. If the -// receiver is actually declared as a non-pointer type, then we copy -// the value into a local variable, so that it has the right type. In -// this function we create the real PARM_DECL to use, and set -// DEC_INITIAL of the var_decl to be the value passed in. - -tree -Function::make_receiver_parm_decl(Gogo* gogo, Named_object* no, tree var_decl) -{ - if (var_decl == error_mark_node) - return error_mark_node; - go_assert(TREE_CODE(var_decl) == VAR_DECL); - tree val_type = TREE_TYPE(var_decl); - bool is_in_heap = no->var_value()->is_in_heap(); - if (is_in_heap) - { - go_assert(POINTER_TYPE_P(val_type)); - val_type = TREE_TYPE(val_type); - } - - source_location loc = DECL_SOURCE_LOCATION(var_decl); - std::string name = IDENTIFIER_POINTER(DECL_NAME(var_decl)); - name += ".pointer"; - tree id = get_identifier_from_string(name); - tree parm_decl = build_decl(loc, PARM_DECL, id, build_pointer_type(val_type)); - DECL_CONTEXT(parm_decl) = current_function_decl; - DECL_ARG_TYPE(parm_decl) = TREE_TYPE(parm_decl); - - go_assert(DECL_INITIAL(var_decl) == NULL_TREE); - tree init = build_fold_indirect_ref_loc(loc, parm_decl); - - if (is_in_heap) - { - tree size = TYPE_SIZE_UNIT(val_type); - tree space = gogo->allocate_memory(no->var_value()->type(), size, - no->location()); - space = save_expr(space); - space = fold_convert(build_pointer_type(val_type), space); - tree spaceref = build_fold_indirect_ref_loc(no->location().gcc_location(), - space); - TREE_THIS_NOTRAP(spaceref) = 1; - tree set = fold_build2_loc(loc, MODIFY_EXPR, void_type_node, - spaceref, init); - init = fold_build2_loc(loc, COMPOUND_EXPR, TREE_TYPE(space), set, space); - } - - DECL_INITIAL(var_decl) = init; - - return parm_decl; -} - -// If we take the address of a parameter, then we need to copy it into -// the heap. We will access it as a local variable via an -// indirection. - -tree -Function::copy_parm_to_heap(Gogo* gogo, Named_object* no, tree var_decl) -{ - if (var_decl == error_mark_node) - return error_mark_node; - go_assert(TREE_CODE(var_decl) == VAR_DECL); - Location loc(DECL_SOURCE_LOCATION(var_decl)); - - std::string name = IDENTIFIER_POINTER(DECL_NAME(var_decl)); - name += ".param"; - tree id = get_identifier_from_string(name); - - tree type = TREE_TYPE(var_decl); - go_assert(POINTER_TYPE_P(type)); - type = TREE_TYPE(type); - - tree parm_decl = build_decl(loc.gcc_location(), PARM_DECL, id, type); - DECL_CONTEXT(parm_decl) = current_function_decl; - DECL_ARG_TYPE(parm_decl) = type; - - tree size = TYPE_SIZE_UNIT(type); - tree space = gogo->allocate_memory(no->var_value()->type(), size, loc); - space = save_expr(space); - space = fold_convert(TREE_TYPE(var_decl), space); - tree spaceref = build_fold_indirect_ref_loc(loc.gcc_location(), space); - TREE_THIS_NOTRAP(spaceref) = 1; - tree init = build2(COMPOUND_EXPR, TREE_TYPE(space), - build2(MODIFY_EXPR, void_type_node, spaceref, parm_decl), - space); - DECL_INITIAL(var_decl) = init; - - return parm_decl; -} - -// Get a tree for function code. - -void -Function::build_tree(Gogo* gogo, Named_object* named_function) -{ - tree fndecl = this->fndecl_; - go_assert(fndecl != NULL_TREE); - - tree params = NULL_TREE; - tree* pp = ¶ms; - - tree declare_vars = NULL_TREE; - for (Bindings::const_definitions_iterator p = - this->block_->bindings()->begin_definitions(); - p != this->block_->bindings()->end_definitions(); - ++p) - { - if ((*p)->is_variable() && (*p)->var_value()->is_parameter()) - { - Bvariable* bvar = (*p)->get_backend_variable(gogo, named_function); - *pp = var_to_tree(bvar); - - // We always pass the receiver to a method as a pointer. If - // the receiver is declared as a non-pointer type, then we - // copy the value into a local variable. - if ((*p)->var_value()->is_receiver() - && (*p)->var_value()->type()->points_to() == NULL) - { - tree parm_decl = this->make_receiver_parm_decl(gogo, *p, *pp); - tree var = *pp; - if (var != error_mark_node) - { - go_assert(TREE_CODE(var) == VAR_DECL); - DECL_CHAIN(var) = declare_vars; - declare_vars = var; - } - *pp = parm_decl; - } - else if ((*p)->var_value()->is_in_heap()) - { - // If we take the address of a parameter, then we need - // to copy it into the heap. - tree parm_decl = this->copy_parm_to_heap(gogo, *p, *pp); - tree var = *pp; - if (var != error_mark_node) - { - go_assert(TREE_CODE(var) == VAR_DECL); - DECL_CHAIN(var) = declare_vars; - declare_vars = var; - } - *pp = parm_decl; - } - - if (*pp != error_mark_node) - { - go_assert(TREE_CODE(*pp) == PARM_DECL); - pp = &DECL_CHAIN(*pp); - } - } - else if ((*p)->is_result_variable()) - { - Bvariable* bvar = (*p)->get_backend_variable(gogo, named_function); - tree var_decl = var_to_tree(bvar); - - Type* type = (*p)->result_var_value()->type(); - tree init; - if (!(*p)->result_var_value()->is_in_heap()) - { - Btype* btype = type->get_backend(gogo); - init = expr_to_tree(gogo->backend()->zero_expression(btype)); - } - else - { - Location loc = (*p)->location(); - tree type_tree = type_to_tree(type->get_backend(gogo)); - tree space = gogo->allocate_memory(type, - TYPE_SIZE_UNIT(type_tree), - loc); - tree ptr_type_tree = build_pointer_type(type_tree); - init = fold_convert_loc(loc.gcc_location(), ptr_type_tree, space); - } - - if (var_decl != error_mark_node) - { - go_assert(TREE_CODE(var_decl) == VAR_DECL); - DECL_INITIAL(var_decl) = init; - DECL_CHAIN(var_decl) = declare_vars; - declare_vars = var_decl; - } - } - } - *pp = NULL_TREE; - - DECL_ARGUMENTS(fndecl) = params; - - if (this->block_ != NULL) - { - go_assert(DECL_INITIAL(fndecl) == NULL_TREE); - - // Declare variables if necessary. - tree bind = NULL_TREE; - tree defer_init = NULL_TREE; - if (declare_vars != NULL_TREE || this->defer_stack_ != NULL) - { - tree block = make_node(BLOCK); - BLOCK_SUPERCONTEXT(block) = fndecl; - DECL_INITIAL(fndecl) = block; - BLOCK_VARS(block) = declare_vars; - TREE_USED(block) = 1; - - bind = build3(BIND_EXPR, void_type_node, BLOCK_VARS(block), - NULL_TREE, block); - TREE_SIDE_EFFECTS(bind) = 1; - - if (this->defer_stack_ != NULL) - { - Translate_context dcontext(gogo, named_function, this->block_, - tree_to_block(bind)); - Bstatement* bdi = this->defer_stack_->get_backend(&dcontext); - defer_init = stat_to_tree(bdi); - } - } - - // Build the trees for all the statements in the function. - Translate_context context(gogo, named_function, NULL, NULL); - Bblock* bblock = this->block_->get_backend(&context); - tree code = block_to_tree(bblock); - - tree init = NULL_TREE; - tree except = NULL_TREE; - tree fini = NULL_TREE; - - // Initialize variables if necessary. - for (tree v = declare_vars; v != NULL_TREE; v = DECL_CHAIN(v)) - { - tree dv = build1(DECL_EXPR, void_type_node, v); - SET_EXPR_LOCATION(dv, DECL_SOURCE_LOCATION(v)); - append_to_statement_list(dv, &init); - } - - // If we have a defer stack, initialize it at the start of a - // function. - if (defer_init != NULL_TREE && defer_init != error_mark_node) - { - SET_EXPR_LOCATION(defer_init, - this->block_->start_location().gcc_location()); - append_to_statement_list(defer_init, &init); - - // Clean up the defer stack when we leave the function. - this->build_defer_wrapper(gogo, named_function, &except, &fini); - } - - if (code != NULL_TREE && code != error_mark_node) - { - if (init != NULL_TREE) - code = build2(COMPOUND_EXPR, void_type_node, init, code); - if (except != NULL_TREE) - code = build2(TRY_CATCH_EXPR, void_type_node, code, - build2(CATCH_EXPR, void_type_node, NULL, except)); - if (fini != NULL_TREE) - code = build2(TRY_FINALLY_EXPR, void_type_node, code, fini); - } - - // Stick the code into the block we built for the receiver, if - // we built on. - if (bind != NULL_TREE && code != NULL_TREE && code != error_mark_node) - { - BIND_EXPR_BODY(bind) = code; - code = bind; - } - - DECL_SAVED_TREE(fndecl) = code; - } -} - -// Build the wrappers around function code needed if the function has -// any defer statements. This sets *EXCEPT to an exception handler -// and *FINI to a finally handler. - -void -Function::build_defer_wrapper(Gogo* gogo, Named_object* named_function, - tree *except, tree *fini) -{ - Location end_loc = this->block_->end_location(); - - // Add an exception handler. This is used if a panic occurs. Its - // purpose is to stop the stack unwinding if a deferred function - // calls recover. There are more details in - // libgo/runtime/go-unwind.c. - - tree stmt_list = NULL_TREE; - - Expression* call = Runtime::make_call(Runtime::CHECK_DEFER, end_loc, 1, - this->defer_stack(end_loc)); - Translate_context context(gogo, named_function, NULL, NULL); - tree call_tree = call->get_tree(&context); - if (call_tree != error_mark_node) - append_to_statement_list(call_tree, &stmt_list); - - tree retval = this->return_value(gogo, named_function, end_loc, &stmt_list); - tree set; - if (retval == NULL_TREE) - set = NULL_TREE; - else - set = fold_build2_loc(end_loc.gcc_location(), MODIFY_EXPR, void_type_node, - DECL_RESULT(this->fndecl_), retval); - tree ret_stmt = fold_build1_loc(end_loc.gcc_location(), RETURN_EXPR, - void_type_node, set); - append_to_statement_list(ret_stmt, &stmt_list); - - go_assert(*except == NULL_TREE); - *except = stmt_list; - - // Add some finally code to run the defer functions. This is used - // both in the normal case, when no panic occurs, and also if a - // panic occurs to run any further defer functions. Of course, it - // is possible for a defer function to call panic which should be - // caught by another defer function. To handle that we use a loop. - // finish: - // try { __go_undefer(); } catch { __go_check_defer(); goto finish; } - // if (return values are named) return named_vals; - - stmt_list = NULL; - - tree label = create_artificial_label(end_loc.gcc_location()); - tree define_label = fold_build1_loc(end_loc.gcc_location(), LABEL_EXPR, - void_type_node, label); - append_to_statement_list(define_label, &stmt_list); - - call = Runtime::make_call(Runtime::UNDEFER, end_loc, 1, - this->defer_stack(end_loc)); - tree undefer = call->get_tree(&context); - - call = Runtime::make_call(Runtime::CHECK_DEFER, end_loc, 1, - this->defer_stack(end_loc)); - tree defer = call->get_tree(&context); - - if (undefer == error_mark_node || defer == error_mark_node) - return; - - tree jump = fold_build1_loc(end_loc.gcc_location(), GOTO_EXPR, void_type_node, - label); - tree catch_body = build2(COMPOUND_EXPR, void_type_node, defer, jump); - catch_body = build2(CATCH_EXPR, void_type_node, NULL, catch_body); - tree try_catch = build2(TRY_CATCH_EXPR, void_type_node, undefer, catch_body); - - append_to_statement_list(try_catch, &stmt_list); - - if (this->type_->results() != NULL - && !this->type_->results()->empty() - && !this->type_->results()->front().name().empty()) - { - // If the result variables are named, and we are returning from - // this function rather than panicing through it, we need to - // return them again, because they might have been changed by a - // defer function. The runtime routines set the defer_stack - // variable to true if we are returning from this function. - retval = this->return_value(gogo, named_function, end_loc, - &stmt_list); - set = fold_build2_loc(end_loc.gcc_location(), MODIFY_EXPR, void_type_node, - DECL_RESULT(this->fndecl_), retval); - ret_stmt = fold_build1_loc(end_loc.gcc_location(), RETURN_EXPR, - void_type_node, set); - - Expression* ref = - Expression::make_temporary_reference(this->defer_stack_, end_loc); - tree tref = ref->get_tree(&context); - tree s = build3_loc(end_loc.gcc_location(), COND_EXPR, void_type_node, - tref, ret_stmt, NULL_TREE); - - append_to_statement_list(s, &stmt_list); - - } - - go_assert(*fini == NULL_TREE); - *fini = stmt_list; -} - -// Return the value to assign to DECL_RESULT(this->fndecl_). This may -// also add statements to STMT_LIST, which need to be executed before -// the assignment. This is used for a return statement with no -// explicit values. - -tree -Function::return_value(Gogo* gogo, Named_object* named_function, - Location location, tree* stmt_list) const -{ - const Typed_identifier_list* results = this->type_->results(); - if (results == NULL || results->empty()) - return NULL_TREE; - - go_assert(this->results_ != NULL); - if (this->results_->size() != results->size()) - { - go_assert(saw_errors()); - return error_mark_node; - } - - tree retval; - if (results->size() == 1) - { - Bvariable* bvar = - this->results_->front()->get_backend_variable(gogo, - named_function); - tree ret = var_to_tree(bvar); - if (this->results_->front()->result_var_value()->is_in_heap()) - ret = build_fold_indirect_ref_loc(location.gcc_location(), ret); - return ret; - } - else - { - tree rettype = TREE_TYPE(DECL_RESULT(this->fndecl_)); - retval = create_tmp_var(rettype, "RESULT"); - tree field = TYPE_FIELDS(rettype); - int index = 0; - for (Typed_identifier_list::const_iterator pr = results->begin(); - pr != results->end(); - ++pr, ++index, field = DECL_CHAIN(field)) - { - go_assert(field != NULL); - Named_object* no = (*this->results_)[index]; - Bvariable* bvar = no->get_backend_variable(gogo, named_function); - tree val = var_to_tree(bvar); - if (no->result_var_value()->is_in_heap()) - val = build_fold_indirect_ref_loc(location.gcc_location(), val); - tree set = fold_build2_loc(location.gcc_location(), MODIFY_EXPR, - void_type_node, - build3(COMPONENT_REF, TREE_TYPE(field), - retval, field, NULL_TREE), - val); - append_to_statement_list(set, stmt_list); - } - return retval; - } -} - -// Return the integer type to use for a size. - -GO_EXTERN_C -tree -go_type_for_size(unsigned int bits, int unsignedp) -{ - const char* name; - switch (bits) - { - case 8: - name = unsignedp ? "uint8" : "int8"; - break; - case 16: - name = unsignedp ? "uint16" : "int16"; - break; - case 32: - name = unsignedp ? "uint32" : "int32"; - break; - case 64: - name = unsignedp ? "uint64" : "int64"; - break; - default: - if (bits == POINTER_SIZE && unsignedp) - name = "uintptr"; - else - return NULL_TREE; - } - Type* type = Type::lookup_integer_type(name); - return type_to_tree(type->get_backend(go_get_gogo())); -} - -// Return the type to use for a mode. - -GO_EXTERN_C -tree -go_type_for_mode(enum machine_mode mode, int unsignedp) -{ - // FIXME: This static_cast should be in machmode.h. - enum mode_class mc = static_cast<enum mode_class>(GET_MODE_CLASS(mode)); - if (mc == MODE_INT) - return go_type_for_size(GET_MODE_BITSIZE(mode), unsignedp); - else if (mc == MODE_FLOAT) - { - Type* type; - switch (GET_MODE_BITSIZE (mode)) - { - case 32: - type = Type::lookup_float_type("float32"); - break; - case 64: - type = Type::lookup_float_type("float64"); - break; - default: - // We have to check for long double in order to support - // i386 excess precision. - if (mode == TYPE_MODE(long_double_type_node)) - return long_double_type_node; - return NULL_TREE; - } - return type_to_tree(type->get_backend(go_get_gogo())); - } - else if (mc == MODE_COMPLEX_FLOAT) - { - Type *type; - switch (GET_MODE_BITSIZE (mode)) - { - case 64: - type = Type::lookup_complex_type("complex64"); - break; - case 128: - type = Type::lookup_complex_type("complex128"); - break; - default: - // We have to check for long double in order to support - // i386 excess precision. - if (mode == TYPE_MODE(complex_long_double_type_node)) - return complex_long_double_type_node; - return NULL_TREE; - } - return type_to_tree(type->get_backend(go_get_gogo())); - } - else - return NULL_TREE; -} - -// Return a tree which allocates SIZE bytes which will holds value of -// type TYPE. - -tree -Gogo::allocate_memory(Type* type, tree size, Location location) -{ - // If the package imports unsafe, then it may play games with - // pointers that look like integers. - if (this->imported_unsafe_ || type->has_pointer()) - { - static tree new_fndecl; - return Gogo::call_builtin(&new_fndecl, - location, - "__go_new", - 1, - ptr_type_node, - sizetype, - size); - } - else - { - static tree new_nopointers_fndecl; - return Gogo::call_builtin(&new_nopointers_fndecl, - location, - "__go_new_nopointers", - 1, - ptr_type_node, - sizetype, - size); - } -} - -// Build a builtin struct with a list of fields. The name is -// STRUCT_NAME. STRUCT_TYPE is NULL_TREE or an empty RECORD_TYPE -// node; this exists so that the struct can have fields which point to -// itself. If PTYPE is not NULL, store the result in *PTYPE. There -// are NFIELDS fields. Each field is a name (a const char*) followed -// by a type (a tree). - -tree -Gogo::builtin_struct(tree* ptype, const char* struct_name, tree struct_type, - int nfields, ...) -{ - if (ptype != NULL && *ptype != NULL_TREE) - return *ptype; - - va_list ap; - va_start(ap, nfields); - - tree fields = NULL_TREE; - for (int i = 0; i < nfields; ++i) - { - const char* field_name = va_arg(ap, const char*); - tree type = va_arg(ap, tree); - if (type == error_mark_node) - { - if (ptype != NULL) - *ptype = error_mark_node; - return error_mark_node; - } - tree field = build_decl(BUILTINS_LOCATION, FIELD_DECL, - get_identifier(field_name), type); - DECL_CHAIN(field) = fields; - fields = field; - } - - va_end(ap); - - if (struct_type == NULL_TREE) - struct_type = make_node(RECORD_TYPE); - finish_builtin_struct(struct_type, struct_name, fields, NULL_TREE); - - if (ptype != NULL) - { - go_preserve_from_gc(struct_type); - *ptype = struct_type; - } - - return struct_type; -} - -// Return a type to use for pointer to const char for a string. - -tree -Gogo::const_char_pointer_type_tree() -{ - static tree type; - if (type == NULL_TREE) - { - tree const_char_type = build_qualified_type(unsigned_char_type_node, - TYPE_QUAL_CONST); - type = build_pointer_type(const_char_type); - go_preserve_from_gc(type); - } - return type; -} - -// Return a tree for a string constant. - -tree -Gogo::string_constant_tree(const std::string& val) -{ - tree index_type = build_index_type(size_int(val.length())); - tree const_char_type = build_qualified_type(unsigned_char_type_node, - TYPE_QUAL_CONST); - tree string_type = build_array_type(const_char_type, index_type); - string_type = build_variant_type_copy(string_type); - TYPE_STRING_FLAG(string_type) = 1; - tree string_val = build_string(val.length(), val.data()); - TREE_TYPE(string_val) = string_type; - return string_val; -} - -// Return a tree for a Go string constant. - -tree -Gogo::go_string_constant_tree(const std::string& val) -{ - tree string_type = type_to_tree(Type::make_string_type()->get_backend(this)); - - vec<constructor_elt, va_gc> *init; - vec_alloc(init, 2); - - constructor_elt empty = {NULL, NULL}; - constructor_elt* elt = init->quick_push(empty); - tree field = TYPE_FIELDS(string_type); - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__data") == 0); - elt->index = field; - tree str = Gogo::string_constant_tree(val); - elt->value = fold_convert(TREE_TYPE(field), - build_fold_addr_expr(str)); - - elt = init->quick_push(empty); - field = DECL_CHAIN(field); - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__length") == 0); - elt->index = field; - elt->value = build_int_cst_type(TREE_TYPE(field), val.length()); - - tree constructor = build_constructor(string_type, init); - TREE_READONLY(constructor) = 1; - TREE_CONSTANT(constructor) = 1; - - return constructor; -} - -// Return a tree for a pointer to a Go string constant. This is only -// used for type descriptors, so we return a pointer to a constant -// decl. - -tree -Gogo::ptr_go_string_constant_tree(const std::string& val) -{ - tree pval = this->go_string_constant_tree(val); - - tree decl = build_decl(UNKNOWN_LOCATION, VAR_DECL, - create_tmp_var_name("SP"), TREE_TYPE(pval)); - DECL_EXTERNAL(decl) = 0; - TREE_PUBLIC(decl) = 0; - TREE_USED(decl) = 1; - TREE_READONLY(decl) = 1; - TREE_CONSTANT(decl) = 1; - TREE_STATIC(decl) = 1; - DECL_ARTIFICIAL(decl) = 1; - DECL_INITIAL(decl) = pval; - rest_of_decl_compilation(decl, 1, 0); - - return build_fold_addr_expr(decl); -} - -// Build a constructor for a slice. SLICE_TYPE_TREE is the type of -// the slice. VALUES is the value pointer and COUNT is the number of -// entries. If CAPACITY is not NULL, it is the capacity; otherwise -// the capacity and the count are the same. - -tree -Gogo::slice_constructor(tree slice_type_tree, tree values, tree count, - tree capacity) -{ - go_assert(TREE_CODE(slice_type_tree) == RECORD_TYPE); - - vec<constructor_elt, va_gc> *init; - vec_alloc(init, 3); - - tree field = TYPE_FIELDS(slice_type_tree); - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__values") == 0); - constructor_elt empty = {NULL, NULL}; - constructor_elt* elt = init->quick_push(empty); - elt->index = field; - go_assert(TYPE_MAIN_VARIANT(TREE_TYPE(field)) - == TYPE_MAIN_VARIANT(TREE_TYPE(values))); - elt->value = values; - - count = fold_convert(sizetype, count); - if (capacity == NULL_TREE) - { - count = save_expr(count); - capacity = count; - } - - field = DECL_CHAIN(field); - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__count") == 0); - elt = init->quick_push(empty); - elt->index = field; - elt->value = fold_convert(TREE_TYPE(field), count); - - field = DECL_CHAIN(field); - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__capacity") == 0); - elt = init->quick_push(empty); - elt->index = field; - elt->value = fold_convert(TREE_TYPE(field), capacity); - - return build_constructor(slice_type_tree, init); -} - -// Build an interface method table for a type: a list of function -// pointers, one for each interface method. This is used for -// interfaces. - -tree -Gogo::interface_method_table_for_type(const Interface_type* interface, - Type* type, bool is_pointer) -{ - const Typed_identifier_list* interface_methods = interface->methods(); - go_assert(!interface_methods->empty()); - - std::string mangled_name = ((is_pointer ? "__go_pimt__" : "__go_imt_") - + interface->mangled_name(this) - + "__" - + type->mangled_name(this)); - - tree id = get_identifier_from_string(mangled_name); - - // See whether this interface has any hidden methods. - bool has_hidden_methods = false; - for (Typed_identifier_list::const_iterator p = interface_methods->begin(); - p != interface_methods->end(); - ++p) - { - if (Gogo::is_hidden_name(p->name())) - { - has_hidden_methods = true; - break; - } - } - - // We already know that the named type is convertible to the - // interface. If the interface has hidden methods, and the named - // type is defined in a different package, then the interface - // conversion table will be defined by that other package. - if (has_hidden_methods - && type->named_type() != NULL - && type->named_type()->named_object()->package() != NULL) - { - tree array_type = build_array_type(const_ptr_type_node, NULL); - tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL, id, array_type); - TREE_READONLY(decl) = 1; - TREE_CONSTANT(decl) = 1; - TREE_PUBLIC(decl) = 1; - DECL_EXTERNAL(decl) = 1; - go_preserve_from_gc(decl); - return decl; - } - - size_t count = interface_methods->size(); - vec<constructor_elt, va_gc> *pointers; - vec_alloc(pointers, count + 1); - - // The first element is the type descriptor. - constructor_elt empty = {NULL, NULL}; - constructor_elt* elt = pointers->quick_push(empty); - elt->index = size_zero_node; - Type* td_type; - if (!is_pointer) - td_type = type; - else - td_type = Type::make_pointer_type(type); - tree tdp = td_type->type_descriptor_pointer(this, - Linemap::predeclared_location()); - elt->value = fold_convert(const_ptr_type_node, tdp); - - Named_type* nt = type->named_type(); - Struct_type* st = type->struct_type(); - go_assert(nt != NULL || st != NULL); - size_t i = 1; - for (Typed_identifier_list::const_iterator p = interface_methods->begin(); - p != interface_methods->end(); - ++p, ++i) - { - bool is_ambiguous; - Method* m; - if (nt != NULL) - m = nt->method_function(p->name(), &is_ambiguous); - else - m = st->method_function(p->name(), &is_ambiguous); - go_assert(m != NULL); - - Named_object* no = m->named_object(); - - tree fnid = no->get_id(this); - - tree fndecl; - if (no->is_function()) - fndecl = no->func_value()->get_or_make_decl(this, no, fnid); - else if (no->is_function_declaration()) - fndecl = no->func_declaration_value()->get_or_make_decl(this, no, - fnid); - else - go_unreachable(); - fndecl = build_fold_addr_expr(fndecl); - - elt = pointers->quick_push(empty); - elt->index = size_int(i); - elt->value = fold_convert(const_ptr_type_node, fndecl); - } - go_assert(i == count + 1); - - tree array_type = build_array_type(const_ptr_type_node, - build_index_type(size_int(count))); - tree constructor = build_constructor(array_type, pointers); - - tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL, id, array_type); - TREE_STATIC(decl) = 1; - TREE_USED(decl) = 1; - TREE_READONLY(decl) = 1; - TREE_CONSTANT(decl) = 1; - DECL_INITIAL(decl) = constructor; - - // If the interface type has hidden methods, then this is the only - // definition of the table. Otherwise it is a comdat table which - // may be defined in multiple packages. - if (has_hidden_methods) - TREE_PUBLIC(decl) = 1; - else - { - make_decl_one_only(decl, DECL_ASSEMBLER_NAME(decl)); - resolve_unique_section(decl, 1, 0); - } - - rest_of_decl_compilation(decl, 1, 0); - - go_preserve_from_gc(decl); - - return decl; -} - -// Mark a function as a builtin library function. - -void -Gogo::mark_fndecl_as_builtin_library(tree fndecl) -{ - DECL_EXTERNAL(fndecl) = 1; - TREE_PUBLIC(fndecl) = 1; - DECL_ARTIFICIAL(fndecl) = 1; - TREE_NOTHROW(fndecl) = 1; - DECL_VISIBILITY(fndecl) = VISIBILITY_DEFAULT; - DECL_VISIBILITY_SPECIFIED(fndecl) = 1; -} - -// Build a call to a builtin function. - -tree -Gogo::call_builtin(tree* pdecl, Location location, const char* name, - int nargs, tree rettype, ...) -{ - if (rettype == error_mark_node) - return error_mark_node; - - tree* types = new tree[nargs]; - tree* args = new tree[nargs]; - - va_list ap; - va_start(ap, rettype); - for (int i = 0; i < nargs; ++i) - { - types[i] = va_arg(ap, tree); - args[i] = va_arg(ap, tree); - if (types[i] == error_mark_node || args[i] == error_mark_node) - { - delete[] types; - delete[] args; - return error_mark_node; - } - } - va_end(ap); - - if (*pdecl == NULL_TREE) - { - tree fnid = get_identifier(name); - - tree argtypes = NULL_TREE; - tree* pp = &argtypes; - for (int i = 0; i < nargs; ++i) - { - *pp = tree_cons(NULL_TREE, types[i], NULL_TREE); - pp = &TREE_CHAIN(*pp); - } - *pp = void_list_node; - - tree fntype = build_function_type(rettype, argtypes); - - *pdecl = build_decl(BUILTINS_LOCATION, FUNCTION_DECL, fnid, fntype); - Gogo::mark_fndecl_as_builtin_library(*pdecl); - go_preserve_from_gc(*pdecl); - } - - tree fnptr = build_fold_addr_expr(*pdecl); - if (CAN_HAVE_LOCATION_P(fnptr)) - SET_EXPR_LOCATION(fnptr, location.gcc_location()); - - tree ret = build_call_array(rettype, fnptr, nargs, args); - SET_EXPR_LOCATION(ret, location.gcc_location()); - - delete[] types; - delete[] args; - - return ret; -} - -// Build a call to the runtime error function. - -tree -Gogo::runtime_error(int code, Location location) -{ - Type* int32_type = Type::lookup_integer_type("int32"); - tree int32_type_tree = type_to_tree(int32_type->get_backend(this)); - - static tree runtime_error_fndecl; - tree ret = Gogo::call_builtin(&runtime_error_fndecl, - location, - "__go_runtime_error", - 1, - void_type_node, - int32_type_tree, - build_int_cst(int32_type_tree, code)); - if (ret == error_mark_node) - return error_mark_node; - // The runtime error function panics and does not return. - TREE_NOTHROW(runtime_error_fndecl) = 0; - TREE_THIS_VOLATILE(runtime_error_fndecl) = 1; - return ret; -} - -// Return a tree for receiving a value of type TYPE_TREE on CHANNEL. -// TYPE_DESCRIPTOR_TREE is the channel's type descriptor. This does a -// blocking receive and returns the value read from the channel. - -tree -Gogo::receive_from_channel(tree type_tree, tree type_descriptor_tree, - tree channel, Location location) -{ - if (type_tree == error_mark_node || channel == error_mark_node) - return error_mark_node; - - if (int_size_in_bytes(type_tree) <= 8 - && !AGGREGATE_TYPE_P(type_tree) - && !FLOAT_TYPE_P(type_tree)) - { - static tree receive_small_fndecl; - tree call = Gogo::call_builtin(&receive_small_fndecl, - location, - "__go_receive_small", - 2, - uint64_type_node, - TREE_TYPE(type_descriptor_tree), - type_descriptor_tree, - ptr_type_node, - channel); - if (call == error_mark_node) - return error_mark_node; - // This can panic if there are too many operations on a closed - // channel. - TREE_NOTHROW(receive_small_fndecl) = 0; - int bitsize = GET_MODE_BITSIZE(TYPE_MODE(type_tree)); - tree int_type_tree = go_type_for_size(bitsize, 1); - return fold_convert_loc(location.gcc_location(), type_tree, - fold_convert_loc(location.gcc_location(), - int_type_tree, call)); - } - else - { - tree tmp = create_tmp_var(type_tree, get_name(type_tree)); - DECL_IGNORED_P(tmp) = 0; - TREE_ADDRESSABLE(tmp) = 1; - tree make_tmp = build1(DECL_EXPR, void_type_node, tmp); - SET_EXPR_LOCATION(make_tmp, location.gcc_location()); - tree tmpaddr = build_fold_addr_expr(tmp); - tmpaddr = fold_convert(ptr_type_node, tmpaddr); - static tree receive_big_fndecl; - tree call = Gogo::call_builtin(&receive_big_fndecl, - location, - "__go_receive_big", - 3, - void_type_node, - TREE_TYPE(type_descriptor_tree), - type_descriptor_tree, - ptr_type_node, - channel, - ptr_type_node, - tmpaddr); - if (call == error_mark_node) - return error_mark_node; - // This can panic if there are too many operations on a closed - // channel. - TREE_NOTHROW(receive_big_fndecl) = 0; - return build2(COMPOUND_EXPR, type_tree, make_tmp, - build2(COMPOUND_EXPR, type_tree, call, tmp)); - } -} - -// Return the type of a function trampoline. This is like -// get_trampoline_type in tree-nested.c. - -tree -Gogo::trampoline_type_tree() -{ - static tree type_tree; - if (type_tree == NULL_TREE) - { - unsigned int size; - unsigned int align; - go_trampoline_info(&size, &align); - tree t = build_index_type(build_int_cst(integer_type_node, size - 1)); - t = build_array_type(char_type_node, t); - - type_tree = Gogo::builtin_struct(NULL, "__go_trampoline", NULL_TREE, 1, - "__data", t); - t = TYPE_FIELDS(type_tree); - DECL_ALIGN(t) = align; - DECL_USER_ALIGN(t) = 1; - - go_preserve_from_gc(type_tree); - } - return type_tree; -} - -// Make a trampoline which calls FNADDR passing CLOSURE. - -tree -Gogo::make_trampoline(tree fnaddr, tree closure, Location location) -{ - tree trampoline_type = Gogo::trampoline_type_tree(); - tree trampoline_size = TYPE_SIZE_UNIT(trampoline_type); - - closure = save_expr(closure); - - // We allocate the trampoline using a special function which will - // mark it as executable. - static tree trampoline_fndecl; - tree x = Gogo::call_builtin(&trampoline_fndecl, - location, - "__go_allocate_trampoline", - 2, - ptr_type_node, - size_type_node, - trampoline_size, - ptr_type_node, - fold_convert_loc(location.gcc_location(), - ptr_type_node, closure)); - if (x == error_mark_node) - return error_mark_node; - - x = save_expr(x); - - // Initialize the trampoline. - tree calldecl = builtin_decl_implicit(BUILT_IN_INIT_HEAP_TRAMPOLINE); - tree ini = build_call_expr(calldecl, 3, x, fnaddr, closure); - - // On some targets the trampoline address needs to be adjusted. For - // example, when compiling in Thumb mode on the ARM, the address - // needs to have the low bit set. - x = build_call_expr(builtin_decl_explicit(BUILT_IN_ADJUST_TRAMPOLINE), 1, x); - x = fold_convert(TREE_TYPE(fnaddr), x); - - return build2(COMPOUND_EXPR, TREE_TYPE(x), ini, x); -} diff --git a/gcc-4.8.1/gcc/go/gofrontend/gogo.cc b/gcc-4.8.1/gcc/go/gofrontend/gogo.cc deleted file mode 100644 index 80ae8d464..000000000 --- a/gcc-4.8.1/gcc/go/gofrontend/gogo.cc +++ /dev/null @@ -1,5572 +0,0 @@ -// gogo.cc -- Go frontend parsed representation. - -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "go-system.h" - -#include "filenames.h" - -#include "go-c.h" -#include "go-dump.h" -#include "lex.h" -#include "types.h" -#include "statements.h" -#include "expressions.h" -#include "dataflow.h" -#include "runtime.h" -#include "import.h" -#include "export.h" -#include "backend.h" -#include "gogo.h" - -// Class Gogo. - -Gogo::Gogo(Backend* backend, Linemap* linemap, int, int pointer_size) - : backend_(backend), - linemap_(linemap), - package_(NULL), - functions_(), - globals_(new Bindings(NULL)), - file_block_names_(), - imports_(), - imported_unsafe_(false), - packages_(), - init_functions_(), - var_deps_(), - need_init_fn_(false), - init_fn_name_(), - imported_init_fns_(), - pkgpath_(), - pkgpath_symbol_(), - prefix_(), - pkgpath_set_(false), - pkgpath_from_option_(false), - prefix_from_option_(false), - relative_import_path_(), - verify_types_(), - interface_types_(), - specific_type_functions_(), - specific_type_functions_are_written_(false), - named_types_are_converted_(false) -{ - const Location loc = Linemap::predeclared_location(); - - Named_type* uint8_type = Type::make_integer_type("uint8", true, 8, - RUNTIME_TYPE_KIND_UINT8); - this->add_named_type(uint8_type); - this->add_named_type(Type::make_integer_type("uint16", true, 16, - RUNTIME_TYPE_KIND_UINT16)); - this->add_named_type(Type::make_integer_type("uint32", true, 32, - RUNTIME_TYPE_KIND_UINT32)); - this->add_named_type(Type::make_integer_type("uint64", true, 64, - RUNTIME_TYPE_KIND_UINT64)); - - this->add_named_type(Type::make_integer_type("int8", false, 8, - RUNTIME_TYPE_KIND_INT8)); - this->add_named_type(Type::make_integer_type("int16", false, 16, - RUNTIME_TYPE_KIND_INT16)); - Named_type* int32_type = Type::make_integer_type("int32", false, 32, - RUNTIME_TYPE_KIND_INT32); - this->add_named_type(int32_type); - this->add_named_type(Type::make_integer_type("int64", false, 64, - RUNTIME_TYPE_KIND_INT64)); - - this->add_named_type(Type::make_float_type("float32", 32, - RUNTIME_TYPE_KIND_FLOAT32)); - this->add_named_type(Type::make_float_type("float64", 64, - RUNTIME_TYPE_KIND_FLOAT64)); - - this->add_named_type(Type::make_complex_type("complex64", 64, - RUNTIME_TYPE_KIND_COMPLEX64)); - this->add_named_type(Type::make_complex_type("complex128", 128, - RUNTIME_TYPE_KIND_COMPLEX128)); - - int int_type_size = pointer_size; - if (int_type_size < 32) - int_type_size = 32; - this->add_named_type(Type::make_integer_type("uint", true, - int_type_size, - RUNTIME_TYPE_KIND_UINT)); - Named_type* int_type = Type::make_integer_type("int", false, int_type_size, - RUNTIME_TYPE_KIND_INT); - this->add_named_type(int_type); - - this->add_named_type(Type::make_integer_type("uintptr", true, - pointer_size, - RUNTIME_TYPE_KIND_UINTPTR)); - - // "byte" is an alias for "uint8". - uint8_type->integer_type()->set_is_byte(); - Named_object* byte_type = Named_object::make_type("byte", NULL, uint8_type, - loc); - this->add_named_type(byte_type->type_value()); - - // "rune" is an alias for "int32". - int32_type->integer_type()->set_is_rune(); - Named_object* rune_type = Named_object::make_type("rune", NULL, int32_type, - loc); - this->add_named_type(rune_type->type_value()); - - this->add_named_type(Type::make_named_bool_type()); - - this->add_named_type(Type::make_named_string_type()); - - // "error" is interface { Error() string }. - { - Typed_identifier_list *methods = new Typed_identifier_list; - Typed_identifier_list *results = new Typed_identifier_list; - results->push_back(Typed_identifier("", Type::lookup_string_type(), loc)); - Type *method_type = Type::make_function_type(NULL, NULL, results, loc); - methods->push_back(Typed_identifier("Error", method_type, loc)); - Interface_type *error_iface = Type::make_interface_type(methods, loc); - error_iface->finalize_methods(); - Named_type *error_type = Named_object::make_type("error", NULL, error_iface, loc)->type_value(); - this->add_named_type(error_type); - } - - this->globals_->add_constant(Typed_identifier("true", - Type::make_boolean_type(), - loc), - NULL, - Expression::make_boolean(true, loc), - 0); - this->globals_->add_constant(Typed_identifier("false", - Type::make_boolean_type(), - loc), - NULL, - Expression::make_boolean(false, loc), - 0); - - this->globals_->add_constant(Typed_identifier("nil", Type::make_nil_type(), - loc), - NULL, - Expression::make_nil(loc), - 0); - - Type* abstract_int_type = Type::make_abstract_integer_type(); - this->globals_->add_constant(Typed_identifier("iota", abstract_int_type, - loc), - NULL, - Expression::make_iota(), - 0); - - Function_type* new_type = Type::make_function_type(NULL, NULL, NULL, loc); - new_type->set_is_varargs(); - new_type->set_is_builtin(); - this->globals_->add_function_declaration("new", NULL, new_type, loc); - - Function_type* make_type = Type::make_function_type(NULL, NULL, NULL, loc); - make_type->set_is_varargs(); - make_type->set_is_builtin(); - this->globals_->add_function_declaration("make", NULL, make_type, loc); - - Typed_identifier_list* len_result = new Typed_identifier_list(); - len_result->push_back(Typed_identifier("", int_type, loc)); - Function_type* len_type = Type::make_function_type(NULL, NULL, len_result, - loc); - len_type->set_is_builtin(); - this->globals_->add_function_declaration("len", NULL, len_type, loc); - - Typed_identifier_list* cap_result = new Typed_identifier_list(); - cap_result->push_back(Typed_identifier("", int_type, loc)); - Function_type* cap_type = Type::make_function_type(NULL, NULL, len_result, - loc); - cap_type->set_is_builtin(); - this->globals_->add_function_declaration("cap", NULL, cap_type, loc); - - Function_type* print_type = Type::make_function_type(NULL, NULL, NULL, loc); - print_type->set_is_varargs(); - print_type->set_is_builtin(); - this->globals_->add_function_declaration("print", NULL, print_type, loc); - - print_type = Type::make_function_type(NULL, NULL, NULL, loc); - print_type->set_is_varargs(); - print_type->set_is_builtin(); - this->globals_->add_function_declaration("println", NULL, print_type, loc); - - Type *empty = Type::make_empty_interface_type(loc); - Typed_identifier_list* panic_parms = new Typed_identifier_list(); - panic_parms->push_back(Typed_identifier("e", empty, loc)); - Function_type *panic_type = Type::make_function_type(NULL, panic_parms, - NULL, loc); - panic_type->set_is_builtin(); - this->globals_->add_function_declaration("panic", NULL, panic_type, loc); - - Typed_identifier_list* recover_result = new Typed_identifier_list(); - recover_result->push_back(Typed_identifier("", empty, loc)); - Function_type* recover_type = Type::make_function_type(NULL, NULL, - recover_result, - loc); - recover_type->set_is_builtin(); - this->globals_->add_function_declaration("recover", NULL, recover_type, loc); - - Function_type* close_type = Type::make_function_type(NULL, NULL, NULL, loc); - close_type->set_is_varargs(); - close_type->set_is_builtin(); - this->globals_->add_function_declaration("close", NULL, close_type, loc); - - Typed_identifier_list* copy_result = new Typed_identifier_list(); - copy_result->push_back(Typed_identifier("", int_type, loc)); - Function_type* copy_type = Type::make_function_type(NULL, NULL, - copy_result, loc); - copy_type->set_is_varargs(); - copy_type->set_is_builtin(); - this->globals_->add_function_declaration("copy", NULL, copy_type, loc); - - Function_type* append_type = Type::make_function_type(NULL, NULL, NULL, loc); - append_type->set_is_varargs(); - append_type->set_is_builtin(); - this->globals_->add_function_declaration("append", NULL, append_type, loc); - - Function_type* complex_type = Type::make_function_type(NULL, NULL, NULL, loc); - complex_type->set_is_varargs(); - complex_type->set_is_builtin(); - this->globals_->add_function_declaration("complex", NULL, complex_type, loc); - - Function_type* real_type = Type::make_function_type(NULL, NULL, NULL, loc); - real_type->set_is_varargs(); - real_type->set_is_builtin(); - this->globals_->add_function_declaration("real", NULL, real_type, loc); - - Function_type* imag_type = Type::make_function_type(NULL, NULL, NULL, loc); - imag_type->set_is_varargs(); - imag_type->set_is_builtin(); - this->globals_->add_function_declaration("imag", NULL, imag_type, loc); - - Function_type* delete_type = Type::make_function_type(NULL, NULL, NULL, loc); - delete_type->set_is_varargs(); - delete_type->set_is_builtin(); - this->globals_->add_function_declaration("delete", NULL, delete_type, loc); -} - -// Convert a pkgpath into a string suitable for a symbol. Note that -// this transformation is convenient but imperfect. A -fgo-pkgpath -// option of a/b_c will conflict with a -fgo-pkgpath option of a_b/c, -// possibly leading to link time errors. - -std::string -Gogo::pkgpath_for_symbol(const std::string& pkgpath) -{ - std::string s = pkgpath; - for (size_t i = 0; i < s.length(); ++i) - { - char c = s[i]; - if ((c >= 'a' && c <= 'z') - || (c >= 'A' && c <= 'Z') - || (c >= '0' && c <= '9') - || c == '_' - || c == '.' - || c == '$') - ; - else - s[i] = '_'; - } - return s; -} - -// Get the package path to use for type reflection data. This should -// ideally be unique across the entire link. - -const std::string& -Gogo::pkgpath() const -{ - go_assert(this->pkgpath_set_); - return this->pkgpath_; -} - -// Set the package path from the -fgo-pkgpath command line option. - -void -Gogo::set_pkgpath(const std::string& arg) -{ - go_assert(!this->pkgpath_set_); - this->pkgpath_ = arg; - this->pkgpath_set_ = true; - this->pkgpath_from_option_ = true; -} - -// Get the package path to use for symbol names. - -const std::string& -Gogo::pkgpath_symbol() const -{ - go_assert(this->pkgpath_set_); - return this->pkgpath_symbol_; -} - -// Set the unique prefix to use to determine the package path, from -// the -fgo-prefix command line option. - -void -Gogo::set_prefix(const std::string& arg) -{ - go_assert(!this->prefix_from_option_); - this->prefix_ = arg; - this->prefix_from_option_ = true; -} - -// Munge name for use in an error message. - -std::string -Gogo::message_name(const std::string& name) -{ - return go_localize_identifier(Gogo::unpack_hidden_name(name).c_str()); -} - -// Get the package name. - -const std::string& -Gogo::package_name() const -{ - go_assert(this->package_ != NULL); - return this->package_->package_name(); -} - -// Set the package name. - -void -Gogo::set_package_name(const std::string& package_name, - Location location) -{ - if (this->package_ != NULL) - { - if (this->package_->package_name() != package_name) - error_at(location, "expected package %<%s%>", - Gogo::message_name(this->package_->package_name()).c_str()); - return; - } - - // Now that we know the name of the package we are compiling, set - // the package path to use for reflect.Type.PkgPath and global - // symbol names. - if (!this->pkgpath_set_) - { - if (!this->prefix_from_option_ && package_name == "main") - this->pkgpath_ = package_name; - else - { - if (!this->prefix_from_option_) - this->prefix_ = "go"; - this->pkgpath_ = this->prefix_ + '.' + package_name; - } - this->pkgpath_set_ = true; - } - - this->pkgpath_symbol_ = Gogo::pkgpath_for_symbol(this->pkgpath_); - - this->package_ = this->register_package(this->pkgpath_, location); - this->package_->set_package_name(package_name, location); - - if (this->is_main_package()) - { - // Declare "main" as a function which takes no parameters and - // returns no value. - Location uloc = Linemap::unknown_location(); - this->declare_function("main", - Type::make_function_type (NULL, NULL, NULL, uloc), - uloc); - } -} - -// Return whether this is the "main" package. This is not true if -// -fgo-pkgpath or -fgo-prefix was used. - -bool -Gogo::is_main_package() const -{ - return (this->package_name() == "main" - && !this->pkgpath_from_option_ - && !this->prefix_from_option_); -} - -// Import a package. - -void -Gogo::import_package(const std::string& filename, - const std::string& local_name, - bool is_local_name_exported, - Location location) -{ - if (filename.empty()) - { - error_at(location, "import path is empty"); - return; - } - - const char *pf = filename.data(); - const char *pend = pf + filename.length(); - while (pf < pend) - { - unsigned int c; - int adv = Lex::fetch_char(pf, &c); - if (adv == 0) - { - error_at(location, "import path contains invalid UTF-8 sequence"); - return; - } - if (c == '\0') - { - error_at(location, "import path contains NUL"); - return; - } - if (c < 0x20 || c == 0x7f) - { - error_at(location, "import path contains control character"); - return; - } - if (c == '\\') - { - error_at(location, "import path contains backslash; use slash"); - return; - } - if (Lex::is_unicode_space(c)) - { - error_at(location, "import path contains space character"); - return; - } - if (c < 0x7f && strchr("!\"#$%&'()*,:;<=>?[]^`{|}", c) != NULL) - { - error_at(location, "import path contains invalid character '%c'", c); - return; - } - pf += adv; - } - - if (IS_ABSOLUTE_PATH(filename.c_str())) - { - error_at(location, "import path cannot be absolute path"); - return; - } - - if (filename == "unsafe") - { - this->import_unsafe(local_name, is_local_name_exported, location); - return; - } - - Imports::const_iterator p = this->imports_.find(filename); - if (p != this->imports_.end()) - { - Package* package = p->second; - package->set_location(location); - package->set_is_imported(); - std::string ln = local_name; - bool is_ln_exported = is_local_name_exported; - if (ln.empty()) - { - ln = package->package_name(); - go_assert(!ln.empty()); - is_ln_exported = Lex::is_exported_name(ln); - } - if (ln == ".") - { - Bindings* bindings = package->bindings(); - for (Bindings::const_declarations_iterator p = - bindings->begin_declarations(); - p != bindings->end_declarations(); - ++p) - this->add_named_object(p->second); - } - else if (ln == "_") - package->set_uses_sink_alias(); - else - { - ln = this->pack_hidden_name(ln, is_ln_exported); - this->package_->bindings()->add_package(ln, package); - } - return; - } - - Import::Stream* stream = Import::open_package(filename, location, - this->relative_import_path_); - if (stream == NULL) - { - error_at(location, "import file %qs not found", filename.c_str()); - return; - } - - Import imp(stream, location); - imp.register_builtin_types(this); - Package* package = imp.import(this, local_name, is_local_name_exported); - if (package != NULL) - { - if (package->pkgpath() == this->pkgpath()) - error_at(location, - ("imported package uses same package path as package " - "being compiled (see -fgo-pkgpath option)")); - - this->imports_.insert(std::make_pair(filename, package)); - package->set_is_imported(); - } - - delete stream; -} - -// Add an import control function for an imported package to the list. - -void -Gogo::add_import_init_fn(const std::string& package_name, - const std::string& init_name, int prio) -{ - for (std::set<Import_init>::const_iterator p = - this->imported_init_fns_.begin(); - p != this->imported_init_fns_.end(); - ++p) - { - if (p->init_name() == init_name) - { - // If a test of package P1, built as part of package P1, - // imports package P2, and P2 imports P1 (perhaps - // indirectly), then we will see the same import name with - // different import priorities. That is OK, so don't give - // an error about it. - if (p->package_name() != package_name) - { - error("duplicate package initialization name %qs", - Gogo::message_name(init_name).c_str()); - inform(UNKNOWN_LOCATION, "used by package %qs at priority %d", - Gogo::message_name(p->package_name()).c_str(), - p->priority()); - inform(UNKNOWN_LOCATION, " and by package %qs at priority %d", - Gogo::message_name(package_name).c_str(), prio); - } - return; - } - } - - this->imported_init_fns_.insert(Import_init(package_name, init_name, - prio)); -} - -// Return whether we are at the global binding level. - -bool -Gogo::in_global_scope() const -{ - return this->functions_.empty(); -} - -// Return the current binding contour. - -Bindings* -Gogo::current_bindings() -{ - if (!this->functions_.empty()) - return this->functions_.back().blocks.back()->bindings(); - else if (this->package_ != NULL) - return this->package_->bindings(); - else - return this->globals_; -} - -const Bindings* -Gogo::current_bindings() const -{ - if (!this->functions_.empty()) - return this->functions_.back().blocks.back()->bindings(); - else if (this->package_ != NULL) - return this->package_->bindings(); - else - return this->globals_; -} - -// Return the current block. - -Block* -Gogo::current_block() -{ - if (this->functions_.empty()) - return NULL; - else - return this->functions_.back().blocks.back(); -} - -// Look up a name in the current binding contour. If PFUNCTION is not -// NULL, set it to the function in which the name is defined, or NULL -// if the name is defined in global scope. - -Named_object* -Gogo::lookup(const std::string& name, Named_object** pfunction) const -{ - if (pfunction != NULL) - *pfunction = NULL; - - if (Gogo::is_sink_name(name)) - return Named_object::make_sink(); - - for (Open_functions::const_reverse_iterator p = this->functions_.rbegin(); - p != this->functions_.rend(); - ++p) - { - Named_object* ret = p->blocks.back()->bindings()->lookup(name); - if (ret != NULL) - { - if (pfunction != NULL) - *pfunction = p->function; - return ret; - } - } - - if (this->package_ != NULL) - { - Named_object* ret = this->package_->bindings()->lookup(name); - if (ret != NULL) - { - if (ret->package() != NULL) - ret->package()->set_used(); - return ret; - } - } - - // We do not look in the global namespace. If we did, the global - // namespace would effectively hide names which were defined in - // package scope which we have not yet seen. Instead, - // define_global_names is called after parsing is over to connect - // undefined names at package scope with names defined at global - // scope. - - return NULL; -} - -// Look up a name in the current block, without searching enclosing -// blocks. - -Named_object* -Gogo::lookup_in_block(const std::string& name) const -{ - go_assert(!this->functions_.empty()); - go_assert(!this->functions_.back().blocks.empty()); - return this->functions_.back().blocks.back()->bindings()->lookup_local(name); -} - -// Look up a name in the global namespace. - -Named_object* -Gogo::lookup_global(const char* name) const -{ - return this->globals_->lookup(name); -} - -// Add an imported package. - -Package* -Gogo::add_imported_package(const std::string& real_name, - const std::string& alias_arg, - bool is_alias_exported, - const std::string& pkgpath, - Location location, - bool* padd_to_globals) -{ - Package* ret = this->register_package(pkgpath, location); - ret->set_package_name(real_name, location); - - *padd_to_globals = false; - - if (alias_arg == ".") - *padd_to_globals = true; - else if (alias_arg == "_") - ret->set_uses_sink_alias(); - else - { - std::string alias = alias_arg; - if (alias.empty()) - { - alias = real_name; - is_alias_exported = Lex::is_exported_name(alias); - } - alias = this->pack_hidden_name(alias, is_alias_exported); - Named_object* no = this->package_->bindings()->add_package(alias, ret); - if (!no->is_package()) - return NULL; - } - - return ret; -} - -// Register a package. This package may or may not be imported. This -// returns the Package structure for the package, creating if it -// necessary. LOCATION is the location of the import statement that -// led us to see this package. - -Package* -Gogo::register_package(const std::string& pkgpath, Location location) -{ - Package* package = NULL; - std::pair<Packages::iterator, bool> ins = - this->packages_.insert(std::make_pair(pkgpath, package)); - if (!ins.second) - { - // We have seen this package name before. - package = ins.first->second; - go_assert(package != NULL && package->pkgpath() == pkgpath); - if (Linemap::is_unknown_location(package->location())) - package->set_location(location); - } - else - { - // First time we have seen this package name. - package = new Package(pkgpath, location); - go_assert(ins.first->second == NULL); - ins.first->second = package; - } - - return package; -} - -// Start compiling a function. - -Named_object* -Gogo::start_function(const std::string& name, Function_type* type, - bool add_method_to_type, Location location) -{ - bool at_top_level = this->functions_.empty(); - - Block* block = new Block(NULL, location); - - Function* enclosing = (at_top_level - ? NULL - : this->functions_.back().function->func_value()); - - Function* function = new Function(type, enclosing, block, location); - - if (type->is_method()) - { - const Typed_identifier* receiver = type->receiver(); - Variable* this_param = new Variable(receiver->type(), NULL, false, - true, true, location); - std::string rname = receiver->name(); - if (rname.empty() || Gogo::is_sink_name(rname)) - { - // We need to give receivers a name since they wind up in - // DECL_ARGUMENTS. FIXME. - static unsigned int count; - char buf[50]; - snprintf(buf, sizeof buf, "r.%u", count); - ++count; - rname = buf; - } - block->bindings()->add_variable(rname, NULL, this_param); - } - - const Typed_identifier_list* parameters = type->parameters(); - bool is_varargs = type->is_varargs(); - if (parameters != NULL) - { - for (Typed_identifier_list::const_iterator p = parameters->begin(); - p != parameters->end(); - ++p) - { - Variable* param = new Variable(p->type(), NULL, false, true, false, - location); - if (is_varargs && p + 1 == parameters->end()) - param->set_is_varargs_parameter(); - - std::string pname = p->name(); - if (pname.empty() || Gogo::is_sink_name(pname)) - { - // We need to give parameters a name since they wind up - // in DECL_ARGUMENTS. FIXME. - static unsigned int count; - char buf[50]; - snprintf(buf, sizeof buf, "p.%u", count); - ++count; - pname = buf; - } - block->bindings()->add_variable(pname, NULL, param); - } - } - - function->create_result_variables(this); - - const std::string* pname; - std::string nested_name; - bool is_init = false; - if (Gogo::unpack_hidden_name(name) == "init" && !type->is_method()) - { - if ((type->parameters() != NULL && !type->parameters()->empty()) - || (type->results() != NULL && !type->results()->empty())) - error_at(location, - "func init must have no arguments and no return values"); - // There can be multiple "init" functions, so give them each a - // different name. - static int init_count; - char buf[30]; - snprintf(buf, sizeof buf, ".$init%d", init_count); - ++init_count; - nested_name = buf; - pname = &nested_name; - is_init = true; - } - else if (!name.empty()) - pname = &name; - else - { - // Invent a name for a nested function. - static int nested_count; - char buf[30]; - snprintf(buf, sizeof buf, ".$nested%d", nested_count); - ++nested_count; - nested_name = buf; - pname = &nested_name; - } - - Named_object* ret; - if (Gogo::is_sink_name(*pname)) - { - static int sink_count; - char buf[30]; - snprintf(buf, sizeof buf, ".$sink%d", sink_count); - ++sink_count; - ret = Named_object::make_function(buf, NULL, function); - } - else if (!type->is_method()) - { - ret = this->package_->bindings()->add_function(*pname, NULL, function); - if (!ret->is_function() || ret->func_value() != function) - { - // Redefinition error. Invent a name to avoid knockon - // errors. - static int redefinition_count; - char buf[30]; - snprintf(buf, sizeof buf, ".$redefined%d", redefinition_count); - ++redefinition_count; - ret = this->package_->bindings()->add_function(buf, NULL, function); - } - } - else - { - if (!add_method_to_type) - ret = Named_object::make_function(name, NULL, function); - else - { - go_assert(at_top_level); - Type* rtype = type->receiver()->type(); - - // We want to look through the pointer created by the - // parser, without getting an error if the type is not yet - // defined. - if (rtype->classification() == Type::TYPE_POINTER) - rtype = rtype->points_to(); - - if (rtype->is_error_type()) - ret = Named_object::make_function(name, NULL, function); - else if (rtype->named_type() != NULL) - { - ret = rtype->named_type()->add_method(name, function); - if (!ret->is_function()) - { - // Redefinition error. - ret = Named_object::make_function(name, NULL, function); - } - } - else if (rtype->forward_declaration_type() != NULL) - { - Named_object* type_no = - rtype->forward_declaration_type()->named_object(); - if (type_no->is_unknown()) - { - // If we are seeing methods it really must be a - // type. Declare it as such. An alternative would - // be to support lists of methods for unknown - // expressions. Either way the error messages if - // this is not a type are going to get confusing. - Named_object* declared = - this->declare_package_type(type_no->name(), - type_no->location()); - go_assert(declared - == type_no->unknown_value()->real_named_object()); - } - ret = rtype->forward_declaration_type()->add_method(name, - function); - } - else - go_unreachable(); - } - this->package_->bindings()->add_method(ret); - } - - this->functions_.resize(this->functions_.size() + 1); - Open_function& of(this->functions_.back()); - of.function = ret; - of.blocks.push_back(block); - - if (is_init) - { - this->init_functions_.push_back(ret); - this->need_init_fn_ = true; - } - - return ret; -} - -// Finish compiling a function. - -void -Gogo::finish_function(Location location) -{ - this->finish_block(location); - go_assert(this->functions_.back().blocks.empty()); - this->functions_.pop_back(); -} - -// Return the current function. - -Named_object* -Gogo::current_function() const -{ - go_assert(!this->functions_.empty()); - return this->functions_.back().function; -} - -// Start a new block. - -void -Gogo::start_block(Location location) -{ - go_assert(!this->functions_.empty()); - Block* block = new Block(this->current_block(), location); - this->functions_.back().blocks.push_back(block); -} - -// Finish a block. - -Block* -Gogo::finish_block(Location location) -{ - go_assert(!this->functions_.empty()); - go_assert(!this->functions_.back().blocks.empty()); - Block* block = this->functions_.back().blocks.back(); - this->functions_.back().blocks.pop_back(); - block->set_end_location(location); - return block; -} - -// Add an erroneous name. - -Named_object* -Gogo::add_erroneous_name(const std::string& name) -{ - return this->package_->bindings()->add_erroneous_name(name); -} - -// Add an unknown name. - -Named_object* -Gogo::add_unknown_name(const std::string& name, Location location) -{ - return this->package_->bindings()->add_unknown_name(name, location); -} - -// Declare a function. - -Named_object* -Gogo::declare_function(const std::string& name, Function_type* type, - Location location) -{ - if (!type->is_method()) - return this->current_bindings()->add_function_declaration(name, NULL, type, - location); - else - { - // We don't bother to add this to the list of global - // declarations. - Type* rtype = type->receiver()->type(); - - // We want to look through the pointer created by the - // parser, without getting an error if the type is not yet - // defined. - if (rtype->classification() == Type::TYPE_POINTER) - rtype = rtype->points_to(); - - if (rtype->is_error_type()) - return NULL; - else if (rtype->named_type() != NULL) - return rtype->named_type()->add_method_declaration(name, NULL, type, - location); - else if (rtype->forward_declaration_type() != NULL) - { - Forward_declaration_type* ftype = rtype->forward_declaration_type(); - return ftype->add_method_declaration(name, NULL, type, location); - } - else - go_unreachable(); - } -} - -// Add a label definition. - -Label* -Gogo::add_label_definition(const std::string& label_name, - Location location) -{ - go_assert(!this->functions_.empty()); - Function* func = this->functions_.back().function->func_value(); - Label* label = func->add_label_definition(this, label_name, location); - this->add_statement(Statement::make_label_statement(label, location)); - return label; -} - -// Add a label reference. - -Label* -Gogo::add_label_reference(const std::string& label_name, - Location location, bool issue_goto_errors) -{ - go_assert(!this->functions_.empty()); - Function* func = this->functions_.back().function->func_value(); - return func->add_label_reference(this, label_name, location, - issue_goto_errors); -} - -// Return the current binding state. - -Bindings_snapshot* -Gogo::bindings_snapshot(Location location) -{ - return new Bindings_snapshot(this->current_block(), location); -} - -// Add a statement. - -void -Gogo::add_statement(Statement* statement) -{ - go_assert(!this->functions_.empty() - && !this->functions_.back().blocks.empty()); - this->functions_.back().blocks.back()->add_statement(statement); -} - -// Add a block. - -void -Gogo::add_block(Block* block, Location location) -{ - go_assert(!this->functions_.empty() - && !this->functions_.back().blocks.empty()); - Statement* statement = Statement::make_block_statement(block, location); - this->functions_.back().blocks.back()->add_statement(statement); -} - -// Add a constant. - -Named_object* -Gogo::add_constant(const Typed_identifier& tid, Expression* expr, - int iota_value) -{ - return this->current_bindings()->add_constant(tid, NULL, expr, iota_value); -} - -// Add a type. - -void -Gogo::add_type(const std::string& name, Type* type, Location location) -{ - Named_object* no = this->current_bindings()->add_type(name, NULL, type, - location); - if (!this->in_global_scope() && no->is_type()) - { - Named_object* f = this->functions_.back().function; - unsigned int index; - if (f->is_function()) - index = f->func_value()->new_local_type_index(); - else - index = 0; - no->type_value()->set_in_function(f, index); - } -} - -// Add a named type. - -void -Gogo::add_named_type(Named_type* type) -{ - go_assert(this->in_global_scope()); - this->current_bindings()->add_named_type(type); -} - -// Declare a type. - -Named_object* -Gogo::declare_type(const std::string& name, Location location) -{ - Bindings* bindings = this->current_bindings(); - Named_object* no = bindings->add_type_declaration(name, NULL, location); - if (!this->in_global_scope() && no->is_type_declaration()) - { - Named_object* f = this->functions_.back().function; - unsigned int index; - if (f->is_function()) - index = f->func_value()->new_local_type_index(); - else - index = 0; - no->type_declaration_value()->set_in_function(f, index); - } - return no; -} - -// Declare a type at the package level. - -Named_object* -Gogo::declare_package_type(const std::string& name, Location location) -{ - return this->package_->bindings()->add_type_declaration(name, NULL, location); -} - -// Declare a function at the package level. - -Named_object* -Gogo::declare_package_function(const std::string& name, Function_type* type, - Location location) -{ - return this->package_->bindings()->add_function_declaration(name, NULL, type, - location); -} - -// Define a type which was already declared. - -void -Gogo::define_type(Named_object* no, Named_type* type) -{ - this->current_bindings()->define_type(no, type); -} - -// Add a variable. - -Named_object* -Gogo::add_variable(const std::string& name, Variable* variable) -{ - Named_object* no = this->current_bindings()->add_variable(name, NULL, - variable); - - // In a function the middle-end wants to see a DECL_EXPR node. - if (no != NULL - && no->is_variable() - && !no->var_value()->is_parameter() - && !this->functions_.empty()) - this->add_statement(Statement::make_variable_declaration(no)); - - return no; -} - -// Add a sink--a reference to the blank identifier _. - -Named_object* -Gogo::add_sink() -{ - return Named_object::make_sink(); -} - -// Add a named object. - -void -Gogo::add_named_object(Named_object* no) -{ - this->current_bindings()->add_named_object(no); -} - -// Mark all local variables used. This is used when some types of -// parse error occur. - -void -Gogo::mark_locals_used() -{ - for (Open_functions::iterator pf = this->functions_.begin(); - pf != this->functions_.end(); - ++pf) - { - for (std::vector<Block*>::iterator pb = pf->blocks.begin(); - pb != pf->blocks.end(); - ++pb) - (*pb)->bindings()->mark_locals_used(); - } -} - -// Record that we've seen an interface type. - -void -Gogo::record_interface_type(Interface_type* itype) -{ - this->interface_types_.push_back(itype); -} - -// Return a name for a thunk object. - -std::string -Gogo::thunk_name() -{ - static int thunk_count; - char thunk_name[50]; - snprintf(thunk_name, sizeof thunk_name, "$thunk%d", thunk_count); - ++thunk_count; - return thunk_name; -} - -// Return whether a function is a thunk. - -bool -Gogo::is_thunk(const Named_object* no) -{ - return no->name().compare(0, 6, "$thunk") == 0; -} - -// Define the global names. We do this only after parsing all the -// input files, because the program might define the global names -// itself. - -void -Gogo::define_global_names() -{ - for (Bindings::const_declarations_iterator p = - this->globals_->begin_declarations(); - p != this->globals_->end_declarations(); - ++p) - { - Named_object* global_no = p->second; - std::string name(Gogo::pack_hidden_name(global_no->name(), false)); - Named_object* no = this->package_->bindings()->lookup(name); - if (no == NULL) - continue; - no = no->resolve(); - if (no->is_type_declaration()) - { - if (global_no->is_type()) - { - if (no->type_declaration_value()->has_methods()) - error_at(no->location(), - "may not define methods for global type"); - no->set_type_value(global_no->type_value()); - } - else - { - error_at(no->location(), "expected type"); - Type* errtype = Type::make_error_type(); - Named_object* err = - Named_object::make_type("erroneous_type", NULL, errtype, - Linemap::predeclared_location()); - no->set_type_value(err->type_value()); - } - } - else if (no->is_unknown()) - no->unknown_value()->set_real_named_object(global_no); - } - - // Give an error if any name is defined in both the package block - // and the file block. For example, this can happen if one file - // imports "fmt" and another file defines a global variable fmt. - for (Bindings::const_declarations_iterator p = - this->package_->bindings()->begin_declarations(); - p != this->package_->bindings()->end_declarations(); - ++p) - { - if (p->second->is_unknown() - && p->second->unknown_value()->real_named_object() == NULL) - { - // No point in warning about an undefined name, as we will - // get other errors later anyhow. - continue; - } - File_block_names::const_iterator pf = - this->file_block_names_.find(p->second->name()); - if (pf != this->file_block_names_.end()) - { - std::string n = p->second->message_name(); - error_at(p->second->location(), - "%qs defined as both imported name and global name", - n.c_str()); - inform(pf->second, "%qs imported here", n.c_str()); - } - } -} - -// Clear out names in file scope. - -void -Gogo::clear_file_scope() -{ - this->package_->bindings()->clear_file_scope(this); - - // Warn about packages which were imported but not used. - bool quiet = saw_errors(); - for (Packages::iterator p = this->packages_.begin(); - p != this->packages_.end(); - ++p) - { - Package* package = p->second; - if (package != this->package_ - && package->is_imported() - && !package->used() - && !package->uses_sink_alias() - && !quiet) - error_at(package->location(), "imported and not used: %s", - Gogo::message_name(package->package_name()).c_str()); - package->clear_is_imported(); - package->clear_uses_sink_alias(); - package->clear_used(); - } -} - -// Queue up a type specific function for later writing. These are -// written out in write_specific_type_functions, called after the -// parse tree is lowered. - -void -Gogo::queue_specific_type_function(Type* type, Named_type* name, - const std::string& hash_name, - Function_type* hash_fntype, - const std::string& equal_name, - Function_type* equal_fntype) -{ - go_assert(!this->specific_type_functions_are_written_); - go_assert(!this->in_global_scope()); - Specific_type_function* tsf = new Specific_type_function(type, name, - hash_name, - hash_fntype, - equal_name, - equal_fntype); - this->specific_type_functions_.push_back(tsf); -} - -// Look for types which need specific hash or equality functions. - -class Specific_type_functions : public Traverse -{ - public: - Specific_type_functions(Gogo* gogo) - : Traverse(traverse_types), - gogo_(gogo) - { } - - int - type(Type*); - - private: - Gogo* gogo_; -}; - -int -Specific_type_functions::type(Type* t) -{ - Named_object* hash_fn; - Named_object* equal_fn; - switch (t->classification()) - { - case Type::TYPE_NAMED: - { - Named_type* nt = t->named_type(); - if (!t->compare_is_identity(this->gogo_) && t->is_comparable()) - t->type_functions(this->gogo_, nt, NULL, NULL, &hash_fn, &equal_fn); - - // If this is a struct type, we don't want to make functions - // for the unnamed struct. - Type* rt = nt->real_type(); - if (rt->struct_type() == NULL) - { - if (Type::traverse(rt, this) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - else - { - // If this type is defined in another package, then we don't - // need to worry about the unexported fields. - bool is_defined_elsewhere = nt->named_object()->package() != NULL; - const Struct_field_list* fields = rt->struct_type()->fields(); - for (Struct_field_list::const_iterator p = fields->begin(); - p != fields->end(); - ++p) - { - if (is_defined_elsewhere - && Gogo::is_hidden_name(p->field_name())) - continue; - if (Type::traverse(p->type(), this) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - } - - return TRAVERSE_SKIP_COMPONENTS; - } - - case Type::TYPE_STRUCT: - case Type::TYPE_ARRAY: - if (!t->compare_is_identity(this->gogo_) && t->is_comparable()) - t->type_functions(this->gogo_, NULL, NULL, NULL, &hash_fn, &equal_fn); - break; - - default: - break; - } - - return TRAVERSE_CONTINUE; -} - -// Write out type specific functions. - -void -Gogo::write_specific_type_functions() -{ - Specific_type_functions stf(this); - this->traverse(&stf); - - while (!this->specific_type_functions_.empty()) - { - Specific_type_function* tsf = this->specific_type_functions_.back(); - this->specific_type_functions_.pop_back(); - tsf->type->write_specific_type_functions(this, tsf->name, - tsf->hash_name, - tsf->hash_fntype, - tsf->equal_name, - tsf->equal_fntype); - delete tsf; - } - this->specific_type_functions_are_written_ = true; -} - -// Traverse the tree. - -void -Gogo::traverse(Traverse* traverse) -{ - // Traverse the current package first for consistency. The other - // packages will only contain imported types, constants, and - // declarations. - if (this->package_->bindings()->traverse(traverse, true) == TRAVERSE_EXIT) - return; - for (Packages::const_iterator p = this->packages_.begin(); - p != this->packages_.end(); - ++p) - { - if (p->second != this->package_) - { - if (p->second->bindings()->traverse(traverse, true) == TRAVERSE_EXIT) - break; - } - } -} - -// Add a type to verify. This is used for types of sink variables, in -// order to give appropriate error messages. - -void -Gogo::add_type_to_verify(Type* type) -{ - this->verify_types_.push_back(type); -} - -// Traversal class used to verify types. - -class Verify_types : public Traverse -{ - public: - Verify_types() - : Traverse(traverse_types) - { } - - int - type(Type*); -}; - -// Verify that a type is correct. - -int -Verify_types::type(Type* t) -{ - if (!t->verify()) - return TRAVERSE_SKIP_COMPONENTS; - return TRAVERSE_CONTINUE; -} - -// Verify that all types are correct. - -void -Gogo::verify_types() -{ - Verify_types traverse; - this->traverse(&traverse); - - for (std::vector<Type*>::iterator p = this->verify_types_.begin(); - p != this->verify_types_.end(); - ++p) - (*p)->verify(); - this->verify_types_.clear(); -} - -// Traversal class used to lower parse tree. - -class Lower_parse_tree : public Traverse -{ - public: - Lower_parse_tree(Gogo* gogo, Named_object* function) - : Traverse(traverse_variables - | traverse_constants - | traverse_functions - | traverse_statements - | traverse_expressions), - gogo_(gogo), function_(function), iota_value_(-1), inserter_() - { } - - void - set_inserter(const Statement_inserter* inserter) - { this->inserter_ = *inserter; } - - int - variable(Named_object*); - - int - constant(Named_object*, bool); - - int - function(Named_object*); - - int - statement(Block*, size_t* pindex, Statement*); - - int - expression(Expression**); - - private: - // General IR. - Gogo* gogo_; - // The function we are traversing. - Named_object* function_; - // Value to use for the predeclared constant iota. - int iota_value_; - // Current statement inserter for use by expressions. - Statement_inserter inserter_; -}; - -// Lower variables. - -int -Lower_parse_tree::variable(Named_object* no) -{ - if (!no->is_variable()) - return TRAVERSE_CONTINUE; - - if (no->is_variable() && no->var_value()->is_global()) - { - // Global variables can have loops in their initialization - // expressions. This is handled in lower_init_expression. - no->var_value()->lower_init_expression(this->gogo_, this->function_, - &this->inserter_); - return TRAVERSE_CONTINUE; - } - - // This is a local variable. We are going to return - // TRAVERSE_SKIP_COMPONENTS here because we want to traverse the - // initialization expression when we reach the variable declaration - // statement. However, that means that we need to traverse the type - // ourselves. - if (no->var_value()->has_type()) - { - Type* type = no->var_value()->type(); - if (type != NULL) - { - if (Type::traverse(type, this) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - } - go_assert(!no->var_value()->has_pre_init()); - - return TRAVERSE_SKIP_COMPONENTS; -} - -// Lower constants. We handle constants specially so that we can set -// the right value for the predeclared constant iota. This works in -// conjunction with the way we lower Const_expression objects. - -int -Lower_parse_tree::constant(Named_object* no, bool) -{ - Named_constant* nc = no->const_value(); - - // Don't get into trouble if the constant's initializer expression - // refers to the constant itself. - if (nc->lowering()) - return TRAVERSE_CONTINUE; - nc->set_lowering(); - - go_assert(this->iota_value_ == -1); - this->iota_value_ = nc->iota_value(); - nc->traverse_expression(this); - this->iota_value_ = -1; - - nc->clear_lowering(); - - // We will traverse the expression a second time, but that will be - // fast. - - return TRAVERSE_CONTINUE; -} - -// Lower function closure types. Record the function while lowering -// it, so that we can pass it down when lowering an expression. - -int -Lower_parse_tree::function(Named_object* no) -{ - no->func_value()->set_closure_type(); - - go_assert(this->function_ == NULL); - this->function_ = no; - int t = no->func_value()->traverse(this); - this->function_ = NULL; - - if (t == TRAVERSE_EXIT) - return t; - return TRAVERSE_SKIP_COMPONENTS; -} - -// Lower statement parse trees. - -int -Lower_parse_tree::statement(Block* block, size_t* pindex, Statement* sorig) -{ - // Because we explicitly traverse the statement's contents - // ourselves, we want to skip block statements here. There is - // nothing to lower in a block statement. - if (sorig->is_block_statement()) - return TRAVERSE_CONTINUE; - - Statement_inserter hold_inserter(this->inserter_); - this->inserter_ = Statement_inserter(block, pindex); - - // Lower the expressions first. - int t = sorig->traverse_contents(this); - if (t == TRAVERSE_EXIT) - { - this->inserter_ = hold_inserter; - return t; - } - - // Keep lowering until nothing changes. - Statement* s = sorig; - while (true) - { - Statement* snew = s->lower(this->gogo_, this->function_, block, - &this->inserter_); - if (snew == s) - break; - s = snew; - t = s->traverse_contents(this); - if (t == TRAVERSE_EXIT) - { - this->inserter_ = hold_inserter; - return t; - } - } - - if (s != sorig) - block->replace_statement(*pindex, s); - - this->inserter_ = hold_inserter; - return TRAVERSE_SKIP_COMPONENTS; -} - -// Lower expression parse trees. - -int -Lower_parse_tree::expression(Expression** pexpr) -{ - // We have to lower all subexpressions first, so that we can get - // their type if necessary. This is awkward, because we don't have - // a postorder traversal pass. - if ((*pexpr)->traverse_subexpressions(this) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - // Keep lowering until nothing changes. - while (true) - { - Expression* e = *pexpr; - Expression* enew = e->lower(this->gogo_, this->function_, - &this->inserter_, this->iota_value_); - if (enew == e) - break; - if (enew->traverse_subexpressions(this) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - *pexpr = enew; - } - return TRAVERSE_SKIP_COMPONENTS; -} - -// Lower the parse tree. This is called after the parse is complete, -// when all names should be resolved. - -void -Gogo::lower_parse_tree() -{ - Lower_parse_tree lower_parse_tree(this, NULL); - this->traverse(&lower_parse_tree); -} - -// Lower a block. - -void -Gogo::lower_block(Named_object* function, Block* block) -{ - Lower_parse_tree lower_parse_tree(this, function); - block->traverse(&lower_parse_tree); -} - -// Lower an expression. INSERTER may be NULL, in which case the -// expression had better not need to create any temporaries. - -void -Gogo::lower_expression(Named_object* function, Statement_inserter* inserter, - Expression** pexpr) -{ - Lower_parse_tree lower_parse_tree(this, function); - if (inserter != NULL) - lower_parse_tree.set_inserter(inserter); - lower_parse_tree.expression(pexpr); -} - -// Lower a constant. This is called when lowering a reference to a -// constant. We have to make sure that the constant has already been -// lowered. - -void -Gogo::lower_constant(Named_object* no) -{ - go_assert(no->is_const()); - Lower_parse_tree lower(this, NULL); - lower.constant(no, false); -} - -// Look for interface types to finalize methods of inherited -// interfaces. - -class Finalize_methods : public Traverse -{ - public: - Finalize_methods(Gogo* gogo) - : Traverse(traverse_types), - gogo_(gogo) - { } - - int - type(Type*); - - private: - Gogo* gogo_; -}; - -// Finalize the methods of an interface type. - -int -Finalize_methods::type(Type* t) -{ - // Check the classification so that we don't finalize the methods - // twice for a named interface type. - switch (t->classification()) - { - case Type::TYPE_INTERFACE: - t->interface_type()->finalize_methods(); - break; - - case Type::TYPE_NAMED: - { - // We have to finalize the methods of the real type first. - // But if the real type is a struct type, then we only want to - // finalize the methods of the field types, not of the struct - // type itself. We don't want to add methods to the struct, - // since it has a name. - Named_type* nt = t->named_type(); - Type* rt = nt->real_type(); - if (rt->classification() != Type::TYPE_STRUCT) - { - if (Type::traverse(rt, this) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - else - { - if (rt->struct_type()->traverse_field_types(this) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - - nt->finalize_methods(this->gogo_); - - // If this type is defined in a different package, then finalize the - // types of all the methods, since we won't see them otherwise. - if (nt->named_object()->package() != NULL && nt->has_any_methods()) - { - const Methods* methods = nt->methods(); - for (Methods::const_iterator p = methods->begin(); - p != methods->end(); - ++p) - { - if (Type::traverse(p->second->type(), this) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - } - - // Finalize the types of all methods that are declared but not - // defined, since we won't see the declarations otherwise. - if (nt->named_object()->package() == NULL - && nt->local_methods() != NULL) - { - const Bindings* methods = nt->local_methods(); - for (Bindings::const_declarations_iterator p = - methods->begin_declarations(); - p != methods->end_declarations(); - p++) - { - if (p->second->is_function_declaration()) - { - Type* mt = p->second->func_declaration_value()->type(); - if (Type::traverse(mt, this) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - } - } - - return TRAVERSE_SKIP_COMPONENTS; - } - - case Type::TYPE_STRUCT: - // Traverse the field types first in case there is an embedded - // field with methods that the struct should inherit. - if (t->struct_type()->traverse_field_types(this) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - t->struct_type()->finalize_methods(this->gogo_); - return TRAVERSE_SKIP_COMPONENTS; - - default: - break; - } - - return TRAVERSE_CONTINUE; -} - -// Finalize method lists and build stub methods for types. - -void -Gogo::finalize_methods() -{ - Finalize_methods finalize(this); - this->traverse(&finalize); -} - -// Set types for unspecified variables and constants. - -void -Gogo::determine_types() -{ - Bindings* bindings = this->current_bindings(); - for (Bindings::const_definitions_iterator p = bindings->begin_definitions(); - p != bindings->end_definitions(); - ++p) - { - if ((*p)->is_function()) - (*p)->func_value()->determine_types(); - else if ((*p)->is_variable()) - (*p)->var_value()->determine_type(); - else if ((*p)->is_const()) - (*p)->const_value()->determine_type(); - - // See if a variable requires us to build an initialization - // function. We know that we will see all global variables - // here. - if (!this->need_init_fn_ && (*p)->is_variable()) - { - Variable* variable = (*p)->var_value(); - - // If this is a global variable which requires runtime - // initialization, we need an initialization function. - if (!variable->is_global()) - ; - else if (variable->init() == NULL) - ; - else if (variable->type()->interface_type() != NULL) - this->need_init_fn_ = true; - else if (variable->init()->is_constant()) - ; - else if (!variable->init()->is_composite_literal()) - this->need_init_fn_ = true; - else if (variable->init()->is_nonconstant_composite_literal()) - this->need_init_fn_ = true; - - // If this is a global variable which holds a pointer value, - // then we need an initialization function to register it as a - // GC root. - if (variable->is_global() && variable->type()->has_pointer()) - this->need_init_fn_ = true; - } - } - - // Determine the types of constants in packages. - for (Packages::const_iterator p = this->packages_.begin(); - p != this->packages_.end(); - ++p) - p->second->determine_types(); -} - -// Traversal class used for type checking. - -class Check_types_traverse : public Traverse -{ - public: - Check_types_traverse(Gogo* gogo) - : Traverse(traverse_variables - | traverse_constants - | traverse_functions - | traverse_statements - | traverse_expressions), - gogo_(gogo) - { } - - int - variable(Named_object*); - - int - constant(Named_object*, bool); - - int - function(Named_object*); - - int - statement(Block*, size_t* pindex, Statement*); - - int - expression(Expression**); - - private: - // General IR. - Gogo* gogo_; -}; - -// Check that a variable initializer has the right type. - -int -Check_types_traverse::variable(Named_object* named_object) -{ - if (named_object->is_variable()) - { - Variable* var = named_object->var_value(); - - // Give error if variable type is not defined. - var->type()->base(); - - Expression* init = var->init(); - std::string reason; - if (init != NULL - && !Type::are_assignable(var->type(), init->type(), &reason)) - { - if (reason.empty()) - error_at(var->location(), "incompatible type in initialization"); - else - error_at(var->location(), - "incompatible type in initialization (%s)", - reason.c_str()); - var->clear_init(); - } - else if (!var->is_used() - && !var->is_global() - && !var->is_parameter() - && !var->is_receiver() - && !var->type()->is_error() - && (init == NULL || !init->is_error_expression()) - && !Lex::is_invalid_identifier(named_object->name())) - error_at(var->location(), "%qs declared and not used", - named_object->message_name().c_str()); - } - return TRAVERSE_CONTINUE; -} - -// Check that a constant initializer has the right type. - -int -Check_types_traverse::constant(Named_object* named_object, bool) -{ - Named_constant* constant = named_object->const_value(); - Type* ctype = constant->type(); - if (ctype->integer_type() == NULL - && ctype->float_type() == NULL - && ctype->complex_type() == NULL - && !ctype->is_boolean_type() - && !ctype->is_string_type()) - { - if (ctype->is_nil_type()) - error_at(constant->location(), "const initializer cannot be nil"); - else if (!ctype->is_error()) - error_at(constant->location(), "invalid constant type"); - constant->set_error(); - } - else if (!constant->expr()->is_constant()) - { - error_at(constant->expr()->location(), "expression is not constant"); - constant->set_error(); - } - else if (!Type::are_assignable(constant->type(), constant->expr()->type(), - NULL)) - { - error_at(constant->location(), - "initialization expression has wrong type"); - constant->set_error(); - } - return TRAVERSE_CONTINUE; -} - -// There are no types to check in a function, but this is where we -// issue warnings about labels which are defined but not referenced. - -int -Check_types_traverse::function(Named_object* no) -{ - no->func_value()->check_labels(); - return TRAVERSE_CONTINUE; -} - -// Check that types are valid in a statement. - -int -Check_types_traverse::statement(Block*, size_t*, Statement* s) -{ - s->check_types(this->gogo_); - return TRAVERSE_CONTINUE; -} - -// Check that types are valid in an expression. - -int -Check_types_traverse::expression(Expression** expr) -{ - (*expr)->check_types(this->gogo_); - return TRAVERSE_CONTINUE; -} - -// Check that types are valid. - -void -Gogo::check_types() -{ - Check_types_traverse traverse(this); - this->traverse(&traverse); -} - -// Check the types in a single block. - -void -Gogo::check_types_in_block(Block* block) -{ - Check_types_traverse traverse(this); - block->traverse(&traverse); -} - -// A traversal class used to find a single shortcut operator within an -// expression. - -class Find_shortcut : public Traverse -{ - public: - Find_shortcut() - : Traverse(traverse_blocks - | traverse_statements - | traverse_expressions), - found_(NULL) - { } - - // A pointer to the expression which was found, or NULL if none was - // found. - Expression** - found() const - { return this->found_; } - - protected: - int - block(Block*) - { return TRAVERSE_SKIP_COMPONENTS; } - - int - statement(Block*, size_t*, Statement*) - { return TRAVERSE_SKIP_COMPONENTS; } - - int - expression(Expression**); - - private: - Expression** found_; -}; - -// Find a shortcut expression. - -int -Find_shortcut::expression(Expression** pexpr) -{ - Expression* expr = *pexpr; - Binary_expression* be = expr->binary_expression(); - if (be == NULL) - return TRAVERSE_CONTINUE; - Operator op = be->op(); - if (op != OPERATOR_OROR && op != OPERATOR_ANDAND) - return TRAVERSE_CONTINUE; - go_assert(this->found_ == NULL); - this->found_ = pexpr; - return TRAVERSE_EXIT; -} - -// A traversal class used to turn shortcut operators into explicit if -// statements. - -class Shortcuts : public Traverse -{ - public: - Shortcuts(Gogo* gogo) - : Traverse(traverse_variables - | traverse_statements), - gogo_(gogo) - { } - - protected: - int - variable(Named_object*); - - int - statement(Block*, size_t*, Statement*); - - private: - // Convert a shortcut operator. - Statement* - convert_shortcut(Block* enclosing, Expression** pshortcut); - - // The IR. - Gogo* gogo_; -}; - -// Remove shortcut operators in a single statement. - -int -Shortcuts::statement(Block* block, size_t* pindex, Statement* s) -{ - // FIXME: This approach doesn't work for switch statements, because - // we add the new statements before the whole switch when we need to - // instead add them just before the switch expression. The right - // fix is probably to lower switch statements with nonconstant cases - // to a series of conditionals. - if (s->switch_statement() != NULL) - return TRAVERSE_CONTINUE; - - while (true) - { - Find_shortcut find_shortcut; - - // If S is a variable declaration, then ordinary traversal won't - // do anything. We want to explicitly traverse the - // initialization expression if there is one. - Variable_declaration_statement* vds = s->variable_declaration_statement(); - Expression* init = NULL; - if (vds == NULL) - s->traverse_contents(&find_shortcut); - else - { - init = vds->var()->var_value()->init(); - if (init == NULL) - return TRAVERSE_CONTINUE; - init->traverse(&init, &find_shortcut); - } - Expression** pshortcut = find_shortcut.found(); - if (pshortcut == NULL) - return TRAVERSE_CONTINUE; - - Statement* snew = this->convert_shortcut(block, pshortcut); - block->insert_statement_before(*pindex, snew); - ++*pindex; - - if (pshortcut == &init) - vds->var()->var_value()->set_init(init); - } -} - -// Remove shortcut operators in the initializer of a global variable. - -int -Shortcuts::variable(Named_object* no) -{ - if (no->is_result_variable()) - return TRAVERSE_CONTINUE; - Variable* var = no->var_value(); - Expression* init = var->init(); - if (!var->is_global() || init == NULL) - return TRAVERSE_CONTINUE; - - while (true) - { - Find_shortcut find_shortcut; - init->traverse(&init, &find_shortcut); - Expression** pshortcut = find_shortcut.found(); - if (pshortcut == NULL) - return TRAVERSE_CONTINUE; - - Statement* snew = this->convert_shortcut(NULL, pshortcut); - var->add_preinit_statement(this->gogo_, snew); - if (pshortcut == &init) - var->set_init(init); - } -} - -// Given an expression which uses a shortcut operator, return a -// statement which implements it, and update *PSHORTCUT accordingly. - -Statement* -Shortcuts::convert_shortcut(Block* enclosing, Expression** pshortcut) -{ - Binary_expression* shortcut = (*pshortcut)->binary_expression(); - Expression* left = shortcut->left(); - Expression* right = shortcut->right(); - Location loc = shortcut->location(); - - Block* retblock = new Block(enclosing, loc); - retblock->set_end_location(loc); - - Temporary_statement* ts = Statement::make_temporary(Type::lookup_bool_type(), - left, loc); - retblock->add_statement(ts); - - Block* block = new Block(retblock, loc); - block->set_end_location(loc); - Expression* tmpref = Expression::make_temporary_reference(ts, loc); - Statement* assign = Statement::make_assignment(tmpref, right, loc); - block->add_statement(assign); - - Expression* cond = Expression::make_temporary_reference(ts, loc); - if (shortcut->binary_expression()->op() == OPERATOR_OROR) - cond = Expression::make_unary(OPERATOR_NOT, cond, loc); - - Statement* if_statement = Statement::make_if_statement(cond, block, NULL, - loc); - retblock->add_statement(if_statement); - - *pshortcut = Expression::make_temporary_reference(ts, loc); - - delete shortcut; - - // Now convert any shortcut operators in LEFT and RIGHT. - Shortcuts shortcuts(this->gogo_); - retblock->traverse(&shortcuts); - - return Statement::make_block_statement(retblock, loc); -} - -// Turn shortcut operators into explicit if statements. Doing this -// considerably simplifies the order of evaluation rules. - -void -Gogo::remove_shortcuts() -{ - Shortcuts shortcuts(this); - this->traverse(&shortcuts); -} - -// A traversal class which finds all the expressions which must be -// evaluated in order within a statement or larger expression. This -// is used to implement the rules about order of evaluation. - -class Find_eval_ordering : public Traverse -{ - private: - typedef std::vector<Expression**> Expression_pointers; - - public: - Find_eval_ordering() - : Traverse(traverse_blocks - | traverse_statements - | traverse_expressions), - exprs_() - { } - - size_t - size() const - { return this->exprs_.size(); } - - typedef Expression_pointers::const_iterator const_iterator; - - const_iterator - begin() const - { return this->exprs_.begin(); } - - const_iterator - end() const - { return this->exprs_.end(); } - - protected: - int - block(Block*) - { return TRAVERSE_SKIP_COMPONENTS; } - - int - statement(Block*, size_t*, Statement*) - { return TRAVERSE_SKIP_COMPONENTS; } - - int - expression(Expression**); - - private: - // A list of pointers to expressions with side-effects. - Expression_pointers exprs_; -}; - -// If an expression must be evaluated in order, put it on the list. - -int -Find_eval_ordering::expression(Expression** expression_pointer) -{ - // We have to look at subexpressions before this one. - if ((*expression_pointer)->traverse_subexpressions(this) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - if ((*expression_pointer)->must_eval_in_order()) - this->exprs_.push_back(expression_pointer); - return TRAVERSE_SKIP_COMPONENTS; -} - -// A traversal class for ordering evaluations. - -class Order_eval : public Traverse -{ - public: - Order_eval(Gogo* gogo) - : Traverse(traverse_variables - | traverse_statements), - gogo_(gogo) - { } - - int - variable(Named_object*); - - int - statement(Block*, size_t*, Statement*); - - private: - // The IR. - Gogo* gogo_; -}; - -// Implement the order of evaluation rules for a statement. - -int -Order_eval::statement(Block* block, size_t* pindex, Statement* s) -{ - // FIXME: This approach doesn't work for switch statements, because - // we add the new statements before the whole switch when we need to - // instead add them just before the switch expression. The right - // fix is probably to lower switch statements with nonconstant cases - // to a series of conditionals. - if (s->switch_statement() != NULL) - return TRAVERSE_CONTINUE; - - Find_eval_ordering find_eval_ordering; - - // If S is a variable declaration, then ordinary traversal won't do - // anything. We want to explicitly traverse the initialization - // expression if there is one. - Variable_declaration_statement* vds = s->variable_declaration_statement(); - Expression* init = NULL; - Expression* orig_init = NULL; - if (vds == NULL) - s->traverse_contents(&find_eval_ordering); - else - { - init = vds->var()->var_value()->init(); - if (init == NULL) - return TRAVERSE_CONTINUE; - orig_init = init; - - // It might seem that this could be - // init->traverse_subexpressions. Unfortunately that can fail - // in a case like - // var err os.Error - // newvar, err := call(arg()) - // Here newvar will have an init of call result 0 of - // call(arg()). If we only traverse subexpressions, we will - // only find arg(), and we won't bother to move anything out. - // Then we get to the assignment to err, we will traverse the - // whole statement, and this time we will find both call() and - // arg(), and so we will move them out. This will cause them to - // be put into temporary variables before the assignment to err - // but after the declaration of newvar. To avoid that problem, - // we traverse the entire expression here. - Expression::traverse(&init, &find_eval_ordering); - } - - size_t c = find_eval_ordering.size(); - if (c == 0) - return TRAVERSE_CONTINUE; - - // If there is only one expression with a side-effect, we can - // usually leave it in place. However, for an assignment statement, - // we need to evaluate an expression on the right hand side before - // we evaluate any index expression on the left hand side, so for - // that case we always move the expression. Otherwise we mishandle - // m[0] = len(m) where m is a map. - if (c == 1 && s->classification() != Statement::STATEMENT_ASSIGNMENT) - return TRAVERSE_CONTINUE; - - bool is_thunk = s->thunk_statement() != NULL; - for (Find_eval_ordering::const_iterator p = find_eval_ordering.begin(); - p != find_eval_ordering.end(); - ++p) - { - Expression** pexpr = *p; - - // The last expression in a thunk will be the call passed to go - // or defer, which we must not evaluate early. - if (is_thunk && p + 1 == find_eval_ordering.end()) - break; - - Location loc = (*pexpr)->location(); - Statement* s; - if ((*pexpr)->call_expression() == NULL - || (*pexpr)->call_expression()->result_count() < 2) - { - Temporary_statement* ts = Statement::make_temporary(NULL, *pexpr, - loc); - s = ts; - *pexpr = Expression::make_temporary_reference(ts, loc); - } - else - { - // A call expression which returns multiple results needs to - // be handled specially. We can't create a temporary - // because there is no type to give it. Any actual uses of - // the values will be done via Call_result_expressions. - s = Statement::make_statement(*pexpr, true); - } - - block->insert_statement_before(*pindex, s); - ++*pindex; - } - - if (init != orig_init) - vds->var()->var_value()->set_init(init); - - return TRAVERSE_CONTINUE; -} - -// Implement the order of evaluation rules for the initializer of a -// global variable. - -int -Order_eval::variable(Named_object* no) -{ - if (no->is_result_variable()) - return TRAVERSE_CONTINUE; - Variable* var = no->var_value(); - Expression* init = var->init(); - if (!var->is_global() || init == NULL) - return TRAVERSE_CONTINUE; - - Find_eval_ordering find_eval_ordering; - Expression::traverse(&init, &find_eval_ordering); - - if (find_eval_ordering.size() <= 1) - { - // If there is only one expression with a side-effect, we can - // leave it in place. - return TRAVERSE_SKIP_COMPONENTS; - } - - Expression* orig_init = init; - - for (Find_eval_ordering::const_iterator p = find_eval_ordering.begin(); - p != find_eval_ordering.end(); - ++p) - { - Expression** pexpr = *p; - Location loc = (*pexpr)->location(); - Statement* s; - if ((*pexpr)->call_expression() == NULL - || (*pexpr)->call_expression()->result_count() < 2) - { - Temporary_statement* ts = Statement::make_temporary(NULL, *pexpr, - loc); - s = ts; - *pexpr = Expression::make_temporary_reference(ts, loc); - } - else - { - // A call expression which returns multiple results needs to - // be handled specially. - s = Statement::make_statement(*pexpr, true); - } - var->add_preinit_statement(this->gogo_, s); - } - - if (init != orig_init) - var->set_init(init); - - return TRAVERSE_SKIP_COMPONENTS; -} - -// Use temporary variables to implement the order of evaluation rules. - -void -Gogo::order_evaluations() -{ - Order_eval order_eval(this); - this->traverse(&order_eval); -} - -// Traversal to convert calls to the predeclared recover function to -// pass in an argument indicating whether it can recover from a panic -// or not. - -class Convert_recover : public Traverse -{ - public: - Convert_recover(Named_object* arg) - : Traverse(traverse_expressions), - arg_(arg) - { } - - protected: - int - expression(Expression**); - - private: - // The argument to pass to the function. - Named_object* arg_; -}; - -// Convert calls to recover. - -int -Convert_recover::expression(Expression** pp) -{ - Call_expression* ce = (*pp)->call_expression(); - if (ce != NULL && ce->is_recover_call()) - ce->set_recover_arg(Expression::make_var_reference(this->arg_, - ce->location())); - return TRAVERSE_CONTINUE; -} - -// Traversal for build_recover_thunks. - -class Build_recover_thunks : public Traverse -{ - public: - Build_recover_thunks(Gogo* gogo) - : Traverse(traverse_functions), - gogo_(gogo) - { } - - int - function(Named_object*); - - private: - Expression* - can_recover_arg(Location); - - // General IR. - Gogo* gogo_; -}; - -// If this function calls recover, turn it into a thunk. - -int -Build_recover_thunks::function(Named_object* orig_no) -{ - Function* orig_func = orig_no->func_value(); - if (!orig_func->calls_recover() - || orig_func->is_recover_thunk() - || orig_func->has_recover_thunk()) - return TRAVERSE_CONTINUE; - - Gogo* gogo = this->gogo_; - Location location = orig_func->location(); - - static int count; - char buf[50]; - - Function_type* orig_fntype = orig_func->type(); - Typed_identifier_list* new_params = new Typed_identifier_list(); - std::string receiver_name; - if (orig_fntype->is_method()) - { - const Typed_identifier* receiver = orig_fntype->receiver(); - snprintf(buf, sizeof buf, "rt.%u", count); - ++count; - receiver_name = buf; - new_params->push_back(Typed_identifier(receiver_name, receiver->type(), - receiver->location())); - } - const Typed_identifier_list* orig_params = orig_fntype->parameters(); - if (orig_params != NULL && !orig_params->empty()) - { - for (Typed_identifier_list::const_iterator p = orig_params->begin(); - p != orig_params->end(); - ++p) - { - snprintf(buf, sizeof buf, "pt.%u", count); - ++count; - new_params->push_back(Typed_identifier(buf, p->type(), - p->location())); - } - } - snprintf(buf, sizeof buf, "pr.%u", count); - ++count; - std::string can_recover_name = buf; - new_params->push_back(Typed_identifier(can_recover_name, - Type::lookup_bool_type(), - orig_fntype->location())); - - const Typed_identifier_list* orig_results = orig_fntype->results(); - Typed_identifier_list* new_results; - if (orig_results == NULL || orig_results->empty()) - new_results = NULL; - else - { - new_results = new Typed_identifier_list(); - for (Typed_identifier_list::const_iterator p = orig_results->begin(); - p != orig_results->end(); - ++p) - new_results->push_back(Typed_identifier("", p->type(), p->location())); - } - - Function_type *new_fntype = Type::make_function_type(NULL, new_params, - new_results, - orig_fntype->location()); - if (orig_fntype->is_varargs()) - new_fntype->set_is_varargs(); - - std::string name = orig_no->name() + "$recover"; - Named_object *new_no = gogo->start_function(name, new_fntype, false, - location); - Function *new_func = new_no->func_value(); - if (orig_func->enclosing() != NULL) - new_func->set_enclosing(orig_func->enclosing()); - - // We build the code for the original function attached to the new - // function, and then swap the original and new function bodies. - // This means that existing references to the original function will - // then refer to the new function. That makes this code a little - // confusing, in that the reference to NEW_NO really refers to the - // other function, not the one we are building. - - Expression* closure = NULL; - if (orig_func->needs_closure()) - { - Named_object* orig_closure_no = orig_func->closure_var(); - Variable* orig_closure_var = orig_closure_no->var_value(); - Variable* new_var = new Variable(orig_closure_var->type(), NULL, false, - true, false, location); - snprintf(buf, sizeof buf, "closure.%u", count); - ++count; - Named_object* new_closure_no = Named_object::make_variable(buf, NULL, - new_var); - new_func->set_closure_var(new_closure_no); - closure = Expression::make_var_reference(new_closure_no, location); - } - - Expression* fn = Expression::make_func_reference(new_no, closure, location); - - Expression_list* args = new Expression_list(); - if (new_params != NULL) - { - // Note that we skip the last parameter, which is the boolean - // indicating whether recover can succed. - for (Typed_identifier_list::const_iterator p = new_params->begin(); - p + 1 != new_params->end(); - ++p) - { - Named_object* p_no = gogo->lookup(p->name(), NULL); - go_assert(p_no != NULL - && p_no->is_variable() - && p_no->var_value()->is_parameter()); - args->push_back(Expression::make_var_reference(p_no, location)); - } - } - args->push_back(this->can_recover_arg(location)); - - gogo->start_block(location); - - Call_expression* call = Expression::make_call(fn, args, false, location); - - // Any varargs call has already been lowered. - call->set_varargs_are_lowered(); - - Statement* s; - if (orig_fntype->results() == NULL || orig_fntype->results()->empty()) - s = Statement::make_statement(call, true); - else - { - Expression_list* vals = new Expression_list(); - size_t rc = orig_fntype->results()->size(); - if (rc == 1) - vals->push_back(call); - else - { - for (size_t i = 0; i < rc; ++i) - vals->push_back(Expression::make_call_result(call, i)); - } - s = Statement::make_return_statement(vals, location); - } - s->determine_types(); - gogo->add_statement(s); - - Block* b = gogo->finish_block(location); - - gogo->add_block(b, location); - - // Lower the call in case it returns multiple results. - gogo->lower_block(new_no, b); - - gogo->finish_function(location); - - // Swap the function bodies and types. - new_func->swap_for_recover(orig_func); - orig_func->set_is_recover_thunk(); - new_func->set_calls_recover(); - new_func->set_has_recover_thunk(); - - Bindings* orig_bindings = orig_func->block()->bindings(); - Bindings* new_bindings = new_func->block()->bindings(); - if (orig_fntype->is_method()) - { - // We changed the receiver to be a regular parameter. We have - // to update the binding accordingly in both functions. - Named_object* orig_rec_no = orig_bindings->lookup_local(receiver_name); - go_assert(orig_rec_no != NULL - && orig_rec_no->is_variable() - && !orig_rec_no->var_value()->is_receiver()); - orig_rec_no->var_value()->set_is_receiver(); - - const std::string& new_receiver_name(orig_fntype->receiver()->name()); - Named_object* new_rec_no = new_bindings->lookup_local(new_receiver_name); - if (new_rec_no == NULL) - go_assert(saw_errors()); - else - { - go_assert(new_rec_no->is_variable() - && new_rec_no->var_value()->is_receiver()); - new_rec_no->var_value()->set_is_not_receiver(); - } - } - - // Because we flipped blocks but not types, the can_recover - // parameter appears in the (now) old bindings as a parameter. - // Change it to a local variable, whereupon it will be discarded. - Named_object* can_recover_no = orig_bindings->lookup_local(can_recover_name); - go_assert(can_recover_no != NULL - && can_recover_no->is_variable() - && can_recover_no->var_value()->is_parameter()); - orig_bindings->remove_binding(can_recover_no); - - // Add the can_recover argument to the (now) new bindings, and - // attach it to any recover statements. - Variable* can_recover_var = new Variable(Type::lookup_bool_type(), NULL, - false, true, false, location); - can_recover_no = new_bindings->add_variable(can_recover_name, NULL, - can_recover_var); - Convert_recover convert_recover(can_recover_no); - new_func->traverse(&convert_recover); - - // Update the function pointers in any named results. - new_func->update_result_variables(); - orig_func->update_result_variables(); - - return TRAVERSE_CONTINUE; -} - -// Return the expression to pass for the .can_recover parameter to the -// new function. This indicates whether a call to recover may return -// non-nil. The expression is -// __go_can_recover(__builtin_return_address()). - -Expression* -Build_recover_thunks::can_recover_arg(Location location) -{ - static Named_object* builtin_return_address; - if (builtin_return_address == NULL) - { - const Location bloc = Linemap::predeclared_location(); - - Typed_identifier_list* param_types = new Typed_identifier_list(); - Type* uint_type = Type::lookup_integer_type("uint"); - param_types->push_back(Typed_identifier("l", uint_type, bloc)); - - Typed_identifier_list* return_types = new Typed_identifier_list(); - Type* voidptr_type = Type::make_pointer_type(Type::make_void_type()); - return_types->push_back(Typed_identifier("", voidptr_type, bloc)); - - Function_type* fntype = Type::make_function_type(NULL, param_types, - return_types, bloc); - builtin_return_address = - Named_object::make_function_declaration("__builtin_return_address", - NULL, fntype, bloc); - const char* n = "__builtin_return_address"; - builtin_return_address->func_declaration_value()->set_asm_name(n); - } - - static Named_object* can_recover; - if (can_recover == NULL) - { - const Location bloc = Linemap::predeclared_location(); - Typed_identifier_list* param_types = new Typed_identifier_list(); - Type* voidptr_type = Type::make_pointer_type(Type::make_void_type()); - param_types->push_back(Typed_identifier("a", voidptr_type, bloc)); - Type* boolean_type = Type::lookup_bool_type(); - Typed_identifier_list* results = new Typed_identifier_list(); - results->push_back(Typed_identifier("", boolean_type, bloc)); - Function_type* fntype = Type::make_function_type(NULL, param_types, - results, bloc); - can_recover = Named_object::make_function_declaration("__go_can_recover", - NULL, fntype, - bloc); - can_recover->func_declaration_value()->set_asm_name("__go_can_recover"); - } - - Expression* fn = Expression::make_func_reference(builtin_return_address, - NULL, location); - - mpz_t zval; - mpz_init_set_ui(zval, 0UL); - Expression* zexpr = Expression::make_integer(&zval, NULL, location); - mpz_clear(zval); - Expression_list *args = new Expression_list(); - args->push_back(zexpr); - - Expression* call = Expression::make_call(fn, args, false, location); - - args = new Expression_list(); - args->push_back(call); - - fn = Expression::make_func_reference(can_recover, NULL, location); - return Expression::make_call(fn, args, false, location); -} - -// Build thunks for functions which call recover. We build a new -// function with an extra parameter, which is whether a call to -// recover can succeed. We then move the body of this function to -// that one. We then turn this function into a thunk which calls the -// new one, passing the value of -// __go_can_recover(__builtin_return_address()). The function will be -// marked as not splitting the stack. This will cooperate with the -// implementation of defer to make recover do the right thing. - -void -Gogo::build_recover_thunks() -{ - Build_recover_thunks build_recover_thunks(this); - this->traverse(&build_recover_thunks); -} - -// Look for named types to see whether we need to create an interface -// method table. - -class Build_method_tables : public Traverse -{ - public: - Build_method_tables(Gogo* gogo, - const std::vector<Interface_type*>& interfaces) - : Traverse(traverse_types), - gogo_(gogo), interfaces_(interfaces) - { } - - int - type(Type*); - - private: - // The IR. - Gogo* gogo_; - // A list of locally defined interfaces which have hidden methods. - const std::vector<Interface_type*>& interfaces_; -}; - -// Build all required interface method tables for types. We need to -// ensure that we have an interface method table for every interface -// which has a hidden method, for every named type which implements -// that interface. Normally we can just build interface method tables -// as we need them. However, in some cases we can require an -// interface method table for an interface defined in a different -// package for a type defined in that package. If that interface and -// type both use a hidden method, that is OK. However, we will not be -// able to build that interface method table when we need it, because -// the type's hidden method will be static. So we have to build it -// here, and just refer it from other packages as needed. - -void -Gogo::build_interface_method_tables() -{ - if (saw_errors()) - return; - - std::vector<Interface_type*> hidden_interfaces; - hidden_interfaces.reserve(this->interface_types_.size()); - for (std::vector<Interface_type*>::const_iterator pi = - this->interface_types_.begin(); - pi != this->interface_types_.end(); - ++pi) - { - const Typed_identifier_list* methods = (*pi)->methods(); - if (methods == NULL) - continue; - for (Typed_identifier_list::const_iterator pm = methods->begin(); - pm != methods->end(); - ++pm) - { - if (Gogo::is_hidden_name(pm->name())) - { - hidden_interfaces.push_back(*pi); - break; - } - } - } - - if (!hidden_interfaces.empty()) - { - // Now traverse the tree looking for all named types. - Build_method_tables bmt(this, hidden_interfaces); - this->traverse(&bmt); - } - - // We no longer need the list of interfaces. - - this->interface_types_.clear(); -} - -// This is called for each type. For a named type, for each of the -// interfaces with hidden methods that it implements, create the -// method table. - -int -Build_method_tables::type(Type* type) -{ - Named_type* nt = type->named_type(); - Struct_type* st = type->struct_type(); - if (nt != NULL || st != NULL) - { - for (std::vector<Interface_type*>::const_iterator p = - this->interfaces_.begin(); - p != this->interfaces_.end(); - ++p) - { - // We ask whether a pointer to the named type implements the - // interface, because a pointer can implement more methods - // than a value. - if (nt != NULL) - { - if ((*p)->implements_interface(Type::make_pointer_type(nt), - NULL)) - { - nt->interface_method_table(this->gogo_, *p, false); - nt->interface_method_table(this->gogo_, *p, true); - } - } - else - { - if ((*p)->implements_interface(Type::make_pointer_type(st), - NULL)) - { - st->interface_method_table(this->gogo_, *p, false); - st->interface_method_table(this->gogo_, *p, true); - } - } - } - } - return TRAVERSE_CONTINUE; -} - -// Traversal class used to check for return statements. - -class Check_return_statements_traverse : public Traverse -{ - public: - Check_return_statements_traverse() - : Traverse(traverse_functions) - { } - - int - function(Named_object*); -}; - -// Check that a function has a return statement if it needs one. - -int -Check_return_statements_traverse::function(Named_object* no) -{ - Function* func = no->func_value(); - const Function_type* fntype = func->type(); - const Typed_identifier_list* results = fntype->results(); - - // We only need a return statement if there is a return value. - if (results == NULL || results->empty()) - return TRAVERSE_CONTINUE; - - if (func->block()->may_fall_through()) - error_at(func->location(), "control reaches end of non-void function"); - - return TRAVERSE_CONTINUE; -} - -// Check return statements. - -void -Gogo::check_return_statements() -{ - Check_return_statements_traverse traverse; - this->traverse(&traverse); -} - -// Work out the package priority. It is one more than the maximum -// priority of an imported package. - -int -Gogo::package_priority() const -{ - int priority = 0; - for (Packages::const_iterator p = this->packages_.begin(); - p != this->packages_.end(); - ++p) - if (p->second->priority() > priority) - priority = p->second->priority(); - return priority + 1; -} - -// Export identifiers as requested. - -void -Gogo::do_exports() -{ - // For now we always stream to a section. Later we may want to - // support streaming to a separate file. - Stream_to_section stream; - - Export exp(&stream); - exp.register_builtin_types(this); - exp.export_globals(this->package_name(), - this->pkgpath(), - this->package_priority(), - this->imports_, - (this->need_init_fn_ && !this->is_main_package() - ? this->get_init_fn_name() - : ""), - this->imported_init_fns_, - this->package_->bindings()); -} - -// Find the blocks in order to convert named types defined in blocks. - -class Convert_named_types : public Traverse -{ - public: - Convert_named_types(Gogo* gogo) - : Traverse(traverse_blocks), - gogo_(gogo) - { } - - protected: - int - block(Block* block); - - private: - Gogo* gogo_; -}; - -int -Convert_named_types::block(Block* block) -{ - this->gogo_->convert_named_types_in_bindings(block->bindings()); - return TRAVERSE_CONTINUE; -} - -// Convert all named types to the backend representation. Since named -// types can refer to other types, this needs to be done in the right -// sequence, which is handled by Named_type::convert. Here we arrange -// to call that for each named type. - -void -Gogo::convert_named_types() -{ - this->convert_named_types_in_bindings(this->globals_); - for (Packages::iterator p = this->packages_.begin(); - p != this->packages_.end(); - ++p) - { - Package* package = p->second; - this->convert_named_types_in_bindings(package->bindings()); - } - - Convert_named_types cnt(this); - this->traverse(&cnt); - - // Make all the builtin named types used for type descriptors, and - // then convert them. They will only be written out if they are - // needed. - Type::make_type_descriptor_type(); - Type::make_type_descriptor_ptr_type(); - Function_type::make_function_type_descriptor_type(); - Pointer_type::make_pointer_type_descriptor_type(); - Struct_type::make_struct_type_descriptor_type(); - Array_type::make_array_type_descriptor_type(); - Array_type::make_slice_type_descriptor_type(); - Map_type::make_map_type_descriptor_type(); - Map_type::make_map_descriptor_type(); - Channel_type::make_chan_type_descriptor_type(); - Interface_type::make_interface_type_descriptor_type(); - Type::convert_builtin_named_types(this); - - Runtime::convert_types(this); - - this->named_types_are_converted_ = true; -} - -// Convert all names types in a set of bindings. - -void -Gogo::convert_named_types_in_bindings(Bindings* bindings) -{ - for (Bindings::const_definitions_iterator p = bindings->begin_definitions(); - p != bindings->end_definitions(); - ++p) - { - if ((*p)->is_type()) - (*p)->type_value()->convert(this); - } -} - -// Class Function. - -Function::Function(Function_type* type, Function* enclosing, Block* block, - Location location) - : type_(type), enclosing_(enclosing), results_(NULL), - closure_var_(NULL), block_(block), location_(location), labels_(), - local_type_count_(0), fndecl_(NULL), defer_stack_(NULL), - results_are_named_(false), nointerface_(false), calls_recover_(false), - is_recover_thunk_(false), has_recover_thunk_(false), - in_unique_section_(false) -{ -} - -// Create the named result variables. - -void -Function::create_result_variables(Gogo* gogo) -{ - const Typed_identifier_list* results = this->type_->results(); - if (results == NULL || results->empty()) - return; - - if (!results->front().name().empty()) - this->results_are_named_ = true; - - this->results_ = new Results(); - this->results_->reserve(results->size()); - - Block* block = this->block_; - int index = 0; - for (Typed_identifier_list::const_iterator p = results->begin(); - p != results->end(); - ++p, ++index) - { - std::string name = p->name(); - if (name.empty() || Gogo::is_sink_name(name)) - { - static int result_counter; - char buf[100]; - snprintf(buf, sizeof buf, "$ret%d", result_counter); - ++result_counter; - name = gogo->pack_hidden_name(buf, false); - } - Result_variable* result = new Result_variable(p->type(), this, index, - p->location()); - Named_object* no = block->bindings()->add_result_variable(name, result); - if (no->is_result_variable()) - this->results_->push_back(no); - else - { - static int dummy_result_count; - char buf[100]; - snprintf(buf, sizeof buf, "$dret%d", dummy_result_count); - ++dummy_result_count; - name = gogo->pack_hidden_name(buf, false); - no = block->bindings()->add_result_variable(name, result); - go_assert(no->is_result_variable()); - this->results_->push_back(no); - } - } -} - -// Update the named result variables when cloning a function which -// calls recover. - -void -Function::update_result_variables() -{ - if (this->results_ == NULL) - return; - - for (Results::iterator p = this->results_->begin(); - p != this->results_->end(); - ++p) - (*p)->result_var_value()->set_function(this); -} - -// Return the closure variable, creating it if necessary. - -Named_object* -Function::closure_var() -{ - if (this->closure_var_ == NULL) - { - // We don't know the type of the variable yet. We add fields as - // we find them. - Location loc = this->type_->location(); - Struct_field_list* sfl = new Struct_field_list; - Type* struct_type = Type::make_struct_type(sfl, loc); - Variable* var = new Variable(Type::make_pointer_type(struct_type), - NULL, false, true, false, loc); - var->set_is_used(); - this->closure_var_ = Named_object::make_variable("closure", NULL, var); - // Note that the new variable is not in any binding contour. - } - return this->closure_var_; -} - -// Set the type of the closure variable. - -void -Function::set_closure_type() -{ - if (this->closure_var_ == NULL) - return; - Named_object* closure = this->closure_var_; - Struct_type* st = closure->var_value()->type()->deref()->struct_type(); - unsigned int index = 0; - for (Closure_fields::const_iterator p = this->closure_fields_.begin(); - p != this->closure_fields_.end(); - ++p, ++index) - { - Named_object* no = p->first; - char buf[20]; - snprintf(buf, sizeof buf, "%u", index); - std::string n = no->name() + buf; - Type* var_type; - if (no->is_variable()) - var_type = no->var_value()->type(); - else - var_type = no->result_var_value()->type(); - Type* field_type = Type::make_pointer_type(var_type); - st->push_field(Struct_field(Typed_identifier(n, field_type, p->second))); - } -} - -// Return whether this function is a method. - -bool -Function::is_method() const -{ - return this->type_->is_method(); -} - -// Add a label definition. - -Label* -Function::add_label_definition(Gogo* gogo, const std::string& label_name, - Location location) -{ - Label* lnull = NULL; - std::pair<Labels::iterator, bool> ins = - this->labels_.insert(std::make_pair(label_name, lnull)); - Label* label; - if (ins.second) - { - // This is a new label. - label = new Label(label_name); - ins.first->second = label; - } - else - { - // The label was already in the hash table. - label = ins.first->second; - if (label->is_defined()) - { - error_at(location, "label %qs already defined", - Gogo::message_name(label_name).c_str()); - inform(label->location(), "previous definition of %qs was here", - Gogo::message_name(label_name).c_str()); - return new Label(label_name); - } - } - - label->define(location, gogo->bindings_snapshot(location)); - - // Issue any errors appropriate for any previous goto's to this - // label. - const std::vector<Bindings_snapshot*>& refs(label->refs()); - for (std::vector<Bindings_snapshot*>::const_iterator p = refs.begin(); - p != refs.end(); - ++p) - (*p)->check_goto_to(gogo->current_block()); - label->clear_refs(); - - return label; -} - -// Add a reference to a label. - -Label* -Function::add_label_reference(Gogo* gogo, const std::string& label_name, - Location location, bool issue_goto_errors) -{ - Label* lnull = NULL; - std::pair<Labels::iterator, bool> ins = - this->labels_.insert(std::make_pair(label_name, lnull)); - Label* label; - if (!ins.second) - { - // The label was already in the hash table. - label = ins.first->second; - } - else - { - go_assert(ins.first->second == NULL); - label = new Label(label_name); - ins.first->second = label; - } - - label->set_is_used(); - - if (issue_goto_errors) - { - Bindings_snapshot* snapshot = label->snapshot(); - if (snapshot != NULL) - snapshot->check_goto_from(gogo->current_block(), location); - else - label->add_snapshot_ref(gogo->bindings_snapshot(location)); - } - - return label; -} - -// Warn about labels that are defined but not used. - -void -Function::check_labels() const -{ - for (Labels::const_iterator p = this->labels_.begin(); - p != this->labels_.end(); - p++) - { - Label* label = p->second; - if (!label->is_used()) - error_at(label->location(), "label %qs defined and not used", - Gogo::message_name(label->name()).c_str()); - } -} - -// Swap one function with another. This is used when building the -// thunk we use to call a function which calls recover. It may not -// work for any other case. - -void -Function::swap_for_recover(Function *x) -{ - go_assert(this->enclosing_ == x->enclosing_); - std::swap(this->results_, x->results_); - std::swap(this->closure_var_, x->closure_var_); - std::swap(this->block_, x->block_); - go_assert(this->location_ == x->location_); - go_assert(this->fndecl_ == NULL && x->fndecl_ == NULL); - go_assert(this->defer_stack_ == NULL && x->defer_stack_ == NULL); -} - -// Traverse the tree. - -int -Function::traverse(Traverse* traverse) -{ - unsigned int traverse_mask = traverse->traverse_mask(); - - if ((traverse_mask - & (Traverse::traverse_types | Traverse::traverse_expressions)) - != 0) - { - if (Type::traverse(this->type_, traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - - // FIXME: We should check traverse_functions here if nested - // functions are stored in block bindings. - if (this->block_ != NULL - && (traverse_mask - & (Traverse::traverse_variables - | Traverse::traverse_constants - | Traverse::traverse_blocks - | Traverse::traverse_statements - | Traverse::traverse_expressions - | Traverse::traverse_types)) != 0) - { - if (this->block_->traverse(traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - - return TRAVERSE_CONTINUE; -} - -// Work out types for unspecified variables and constants. - -void -Function::determine_types() -{ - if (this->block_ != NULL) - this->block_->determine_types(); -} - -// Get a pointer to the variable representing the defer stack for this -// function, making it if necessary. The value of the variable is set -// by the runtime routines to true if the function is returning, -// rather than panicing through. A pointer to this variable is used -// as a marker for the functions on the defer stack associated with -// this function. A function-specific variable permits inlining a -// function which uses defer. - -Expression* -Function::defer_stack(Location location) -{ - if (this->defer_stack_ == NULL) - { - Type* t = Type::lookup_bool_type(); - Expression* n = Expression::make_boolean(false, location); - this->defer_stack_ = Statement::make_temporary(t, n, location); - this->defer_stack_->set_is_address_taken(); - } - Expression* ref = Expression::make_temporary_reference(this->defer_stack_, - location); - return Expression::make_unary(OPERATOR_AND, ref, location); -} - -// Export the function. - -void -Function::export_func(Export* exp, const std::string& name) const -{ - Function::export_func_with_type(exp, name, this->type_); -} - -// Export a function with a type. - -void -Function::export_func_with_type(Export* exp, const std::string& name, - const Function_type* fntype) -{ - exp->write_c_string("func "); - - if (fntype->is_method()) - { - exp->write_c_string("("); - const Typed_identifier* receiver = fntype->receiver(); - exp->write_name(receiver->name()); - exp->write_c_string(" "); - exp->write_type(receiver->type()); - exp->write_c_string(") "); - } - - exp->write_string(name); - - exp->write_c_string(" ("); - const Typed_identifier_list* parameters = fntype->parameters(); - if (parameters != NULL) - { - bool is_varargs = fntype->is_varargs(); - bool first = true; - for (Typed_identifier_list::const_iterator p = parameters->begin(); - p != parameters->end(); - ++p) - { - if (first) - first = false; - else - exp->write_c_string(", "); - exp->write_name(p->name()); - exp->write_c_string(" "); - if (!is_varargs || p + 1 != parameters->end()) - exp->write_type(p->type()); - else - { - exp->write_c_string("..."); - exp->write_type(p->type()->array_type()->element_type()); - } - } - } - exp->write_c_string(")"); - - const Typed_identifier_list* results = fntype->results(); - if (results != NULL) - { - if (results->size() == 1 && results->begin()->name().empty()) - { - exp->write_c_string(" "); - exp->write_type(results->begin()->type()); - } - else - { - exp->write_c_string(" ("); - bool first = true; - for (Typed_identifier_list::const_iterator p = results->begin(); - p != results->end(); - ++p) - { - if (first) - first = false; - else - exp->write_c_string(", "); - exp->write_name(p->name()); - exp->write_c_string(" "); - exp->write_type(p->type()); - } - exp->write_c_string(")"); - } - } - exp->write_c_string(";\n"); -} - -// Import a function. - -void -Function::import_func(Import* imp, std::string* pname, - Typed_identifier** preceiver, - Typed_identifier_list** pparameters, - Typed_identifier_list** presults, - bool* is_varargs) -{ - imp->require_c_string("func "); - - *preceiver = NULL; - if (imp->peek_char() == '(') - { - imp->require_c_string("("); - std::string name = imp->read_name(); - imp->require_c_string(" "); - Type* rtype = imp->read_type(); - *preceiver = new Typed_identifier(name, rtype, imp->location()); - imp->require_c_string(") "); - } - - *pname = imp->read_identifier(); - - Typed_identifier_list* parameters; - *is_varargs = false; - imp->require_c_string(" ("); - if (imp->peek_char() == ')') - parameters = NULL; - else - { - parameters = new Typed_identifier_list(); - while (true) - { - std::string name = imp->read_name(); - imp->require_c_string(" "); - - if (imp->match_c_string("...")) - { - imp->advance(3); - *is_varargs = true; - } - - Type* ptype = imp->read_type(); - if (*is_varargs) - ptype = Type::make_array_type(ptype, NULL); - parameters->push_back(Typed_identifier(name, ptype, - imp->location())); - if (imp->peek_char() != ',') - break; - go_assert(!*is_varargs); - imp->require_c_string(", "); - } - } - imp->require_c_string(")"); - *pparameters = parameters; - - Typed_identifier_list* results; - if (imp->peek_char() != ' ') - results = NULL; - else - { - results = new Typed_identifier_list(); - imp->require_c_string(" "); - if (imp->peek_char() != '(') - { - Type* rtype = imp->read_type(); - results->push_back(Typed_identifier("", rtype, imp->location())); - } - else - { - imp->require_c_string("("); - while (true) - { - std::string name = imp->read_name(); - imp->require_c_string(" "); - Type* rtype = imp->read_type(); - results->push_back(Typed_identifier(name, rtype, - imp->location())); - if (imp->peek_char() != ',') - break; - imp->require_c_string(", "); - } - imp->require_c_string(")"); - } - } - imp->require_c_string(";\n"); - *presults = results; -} - -// Class Block. - -Block::Block(Block* enclosing, Location location) - : enclosing_(enclosing), statements_(), - bindings_(new Bindings(enclosing == NULL - ? NULL - : enclosing->bindings())), - start_location_(location), - end_location_(UNKNOWN_LOCATION) -{ -} - -// Add a statement to a block. - -void -Block::add_statement(Statement* statement) -{ - this->statements_.push_back(statement); -} - -// Add a statement to the front of a block. This is slow but is only -// used for reference counts of parameters. - -void -Block::add_statement_at_front(Statement* statement) -{ - this->statements_.insert(this->statements_.begin(), statement); -} - -// Replace a statement in a block. - -void -Block::replace_statement(size_t index, Statement* s) -{ - go_assert(index < this->statements_.size()); - this->statements_[index] = s; -} - -// Add a statement before another statement. - -void -Block::insert_statement_before(size_t index, Statement* s) -{ - go_assert(index < this->statements_.size()); - this->statements_.insert(this->statements_.begin() + index, s); -} - -// Add a statement after another statement. - -void -Block::insert_statement_after(size_t index, Statement* s) -{ - go_assert(index < this->statements_.size()); - this->statements_.insert(this->statements_.begin() + index + 1, s); -} - -// Traverse the tree. - -int -Block::traverse(Traverse* traverse) -{ - unsigned int traverse_mask = traverse->traverse_mask(); - - if ((traverse_mask & Traverse::traverse_blocks) != 0) - { - int t = traverse->block(this); - if (t == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - else if (t == TRAVERSE_SKIP_COMPONENTS) - return TRAVERSE_CONTINUE; - } - - if ((traverse_mask - & (Traverse::traverse_variables - | Traverse::traverse_constants - | Traverse::traverse_expressions - | Traverse::traverse_types)) != 0) - { - const unsigned int e_or_t = (Traverse::traverse_expressions - | Traverse::traverse_types); - const unsigned int e_or_t_or_s = (e_or_t - | Traverse::traverse_statements); - for (Bindings::const_definitions_iterator pb = - this->bindings_->begin_definitions(); - pb != this->bindings_->end_definitions(); - ++pb) - { - int t = TRAVERSE_CONTINUE; - switch ((*pb)->classification()) - { - case Named_object::NAMED_OBJECT_CONST: - if ((traverse_mask & Traverse::traverse_constants) != 0) - t = traverse->constant(*pb, false); - if (t == TRAVERSE_CONTINUE - && (traverse_mask & e_or_t) != 0) - { - Type* tc = (*pb)->const_value()->type(); - if (tc != NULL - && Type::traverse(tc, traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - t = (*pb)->const_value()->traverse_expression(traverse); - } - break; - - case Named_object::NAMED_OBJECT_VAR: - case Named_object::NAMED_OBJECT_RESULT_VAR: - if ((traverse_mask & Traverse::traverse_variables) != 0) - t = traverse->variable(*pb); - if (t == TRAVERSE_CONTINUE - && (traverse_mask & e_or_t) != 0) - { - if ((*pb)->is_result_variable() - || (*pb)->var_value()->has_type()) - { - Type* tv = ((*pb)->is_variable() - ? (*pb)->var_value()->type() - : (*pb)->result_var_value()->type()); - if (tv != NULL - && Type::traverse(tv, traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - } - if (t == TRAVERSE_CONTINUE - && (traverse_mask & e_or_t_or_s) != 0 - && (*pb)->is_variable()) - t = (*pb)->var_value()->traverse_expression(traverse, - traverse_mask); - break; - - case Named_object::NAMED_OBJECT_FUNC: - case Named_object::NAMED_OBJECT_FUNC_DECLARATION: - go_unreachable(); - - case Named_object::NAMED_OBJECT_TYPE: - if ((traverse_mask & e_or_t) != 0) - t = Type::traverse((*pb)->type_value(), traverse); - break; - - case Named_object::NAMED_OBJECT_TYPE_DECLARATION: - case Named_object::NAMED_OBJECT_UNKNOWN: - case Named_object::NAMED_OBJECT_ERRONEOUS: - break; - - case Named_object::NAMED_OBJECT_PACKAGE: - case Named_object::NAMED_OBJECT_SINK: - go_unreachable(); - - default: - go_unreachable(); - } - - if (t == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - } - - // No point in checking traverse_mask here--if we got here we always - // want to walk the statements. The traversal can insert new - // statements before or after the current statement. Inserting - // statements before the current statement requires updating I via - // the pointer; those statements will not be traversed. Any new - // statements inserted after the current statement will be traversed - // in their turn. - for (size_t i = 0; i < this->statements_.size(); ++i) - { - if (this->statements_[i]->traverse(this, &i, traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - - return TRAVERSE_CONTINUE; -} - -// Work out types for unspecified variables and constants. - -void -Block::determine_types() -{ - for (Bindings::const_definitions_iterator pb = - this->bindings_->begin_definitions(); - pb != this->bindings_->end_definitions(); - ++pb) - { - if ((*pb)->is_variable()) - (*pb)->var_value()->determine_type(); - else if ((*pb)->is_const()) - (*pb)->const_value()->determine_type(); - } - - for (std::vector<Statement*>::const_iterator ps = this->statements_.begin(); - ps != this->statements_.end(); - ++ps) - (*ps)->determine_types(); -} - -// Return true if the statements in this block may fall through. - -bool -Block::may_fall_through() const -{ - if (this->statements_.empty()) - return true; - return this->statements_.back()->may_fall_through(); -} - -// Convert a block to the backend representation. - -Bblock* -Block::get_backend(Translate_context* context) -{ - Gogo* gogo = context->gogo(); - Named_object* function = context->function(); - std::vector<Bvariable*> vars; - vars.reserve(this->bindings_->size_definitions()); - for (Bindings::const_definitions_iterator pv = - this->bindings_->begin_definitions(); - pv != this->bindings_->end_definitions(); - ++pv) - { - if ((*pv)->is_variable() && !(*pv)->var_value()->is_parameter()) - vars.push_back((*pv)->get_backend_variable(gogo, function)); - } - - // FIXME: Permitting FUNCTION to be NULL here is a temporary measure - // until we have a proper representation of the init function. - Bfunction* bfunction; - if (function == NULL) - bfunction = NULL; - else - bfunction = tree_to_function(function->func_value()->get_decl()); - Bblock* ret = context->backend()->block(bfunction, context->bblock(), - vars, this->start_location_, - this->end_location_); - - Translate_context subcontext(gogo, function, this, ret); - std::vector<Bstatement*> bstatements; - bstatements.reserve(this->statements_.size()); - for (std::vector<Statement*>::const_iterator p = this->statements_.begin(); - p != this->statements_.end(); - ++p) - bstatements.push_back((*p)->get_backend(&subcontext)); - - context->backend()->block_add_statements(ret, bstatements); - - return ret; -} - -// Class Bindings_snapshot. - -Bindings_snapshot::Bindings_snapshot(const Block* b, Location location) - : block_(b), counts_(), location_(location) -{ - while (b != NULL) - { - this->counts_.push_back(b->bindings()->size_definitions()); - b = b->enclosing(); - } -} - -// Report errors appropriate for a goto from B to this. - -void -Bindings_snapshot::check_goto_from(const Block* b, Location loc) -{ - size_t dummy; - if (!this->check_goto_block(loc, b, this->block_, &dummy)) - return; - this->check_goto_defs(loc, this->block_, - this->block_->bindings()->size_definitions(), - this->counts_[0]); -} - -// Report errors appropriate for a goto from this to B. - -void -Bindings_snapshot::check_goto_to(const Block* b) -{ - size_t index; - if (!this->check_goto_block(this->location_, this->block_, b, &index)) - return; - this->check_goto_defs(this->location_, b, this->counts_[index], - b->bindings()->size_definitions()); -} - -// Report errors appropriate for a goto at LOC from BFROM to BTO. -// Return true if all is well, false if we reported an error. If this -// returns true, it sets *PINDEX to the number of blocks BTO is above -// BFROM. - -bool -Bindings_snapshot::check_goto_block(Location loc, const Block* bfrom, - const Block* bto, size_t* pindex) -{ - // It is an error if BTO is not either BFROM or above BFROM. - size_t index = 0; - for (const Block* pb = bfrom; pb != bto; pb = pb->enclosing(), ++index) - { - if (pb == NULL) - { - error_at(loc, "goto jumps into block"); - inform(bto->start_location(), "goto target block starts here"); - return false; - } - } - *pindex = index; - return true; -} - -// Report errors appropriate for a goto at LOC ending at BLOCK, where -// CFROM is the number of names defined at the point of the goto and -// CTO is the number of names defined at the point of the label. - -void -Bindings_snapshot::check_goto_defs(Location loc, const Block* block, - size_t cfrom, size_t cto) -{ - if (cfrom < cto) - { - Bindings::const_definitions_iterator p = - block->bindings()->begin_definitions(); - for (size_t i = 0; i < cfrom; ++i) - { - go_assert(p != block->bindings()->end_definitions()); - ++p; - } - go_assert(p != block->bindings()->end_definitions()); - - std::string n = (*p)->message_name(); - error_at(loc, "goto jumps over declaration of %qs", n.c_str()); - inform((*p)->location(), "%qs defined here", n.c_str()); - } -} - -// Class Variable. - -Variable::Variable(Type* type, Expression* init, bool is_global, - bool is_parameter, bool is_receiver, - Location location) - : type_(type), init_(init), preinit_(NULL), location_(location), - backend_(NULL), is_global_(is_global), is_parameter_(is_parameter), - is_receiver_(is_receiver), is_varargs_parameter_(false), is_used_(false), - is_address_taken_(false), is_non_escaping_address_taken_(false), - seen_(false), init_is_lowered_(false), type_from_init_tuple_(false), - type_from_range_index_(false), type_from_range_value_(false), - type_from_chan_element_(false), is_type_switch_var_(false), - determined_type_(false), in_unique_section_(false) -{ - go_assert(type != NULL || init != NULL); - go_assert(!is_parameter || init == NULL); -} - -// Traverse the initializer expression. - -int -Variable::traverse_expression(Traverse* traverse, unsigned int traverse_mask) -{ - if (this->preinit_ != NULL) - { - if (this->preinit_->traverse(traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - if (this->init_ != NULL - && ((traverse_mask - & (Traverse::traverse_expressions | Traverse::traverse_types)) - != 0)) - { - if (Expression::traverse(&this->init_, traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - return TRAVERSE_CONTINUE; -} - -// Lower the initialization expression after parsing is complete. - -void -Variable::lower_init_expression(Gogo* gogo, Named_object* function, - Statement_inserter* inserter) -{ - Named_object* dep = gogo->var_depends_on(this); - if (dep != NULL && dep->is_variable()) - dep->var_value()->lower_init_expression(gogo, function, inserter); - - if (this->init_ != NULL && !this->init_is_lowered_) - { - if (this->seen_) - { - // We will give an error elsewhere, this is just to prevent - // an infinite loop. - return; - } - this->seen_ = true; - - Statement_inserter global_inserter; - if (this->is_global_) - { - global_inserter = Statement_inserter(gogo, this); - inserter = &global_inserter; - } - - gogo->lower_expression(function, inserter, &this->init_); - - this->seen_ = false; - - this->init_is_lowered_ = true; - } -} - -// Get the preinit block. - -Block* -Variable::preinit_block(Gogo* gogo) -{ - go_assert(this->is_global_); - if (this->preinit_ == NULL) - this->preinit_ = new Block(NULL, this->location()); - - // If a global variable has a preinitialization statement, then we - // need to have an initialization function. - gogo->set_need_init_fn(); - - return this->preinit_; -} - -// Add a statement to be run before the initialization expression. - -void -Variable::add_preinit_statement(Gogo* gogo, Statement* s) -{ - Block* b = this->preinit_block(gogo); - b->add_statement(s); - b->set_end_location(s->location()); -} - -// Whether this variable has a type. - -bool -Variable::has_type() const -{ - if (this->type_ == NULL) - return false; - - // A variable created in a type switch case nil does not actually - // have a type yet. It will be changed to use the initializer's - // type in determine_type. - if (this->is_type_switch_var_ - && this->type_->is_nil_constant_as_type()) - return false; - - return true; -} - -// In an assignment which sets a variable to a tuple of EXPR, return -// the type of the first element of the tuple. - -Type* -Variable::type_from_tuple(Expression* expr, bool report_error) const -{ - if (expr->map_index_expression() != NULL) - { - Map_type* mt = expr->map_index_expression()->get_map_type(); - if (mt == NULL) - return Type::make_error_type(); - return mt->val_type(); - } - else if (expr->receive_expression() != NULL) - { - Expression* channel = expr->receive_expression()->channel(); - Type* channel_type = channel->type(); - if (channel_type->channel_type() == NULL) - return Type::make_error_type(); - return channel_type->channel_type()->element_type(); - } - else - { - if (report_error) - error_at(this->location(), "invalid tuple definition"); - return Type::make_error_type(); - } -} - -// Given EXPR used in a range clause, return either the index type or -// the value type of the range, depending upon GET_INDEX_TYPE. - -Type* -Variable::type_from_range(Expression* expr, bool get_index_type, - bool report_error) const -{ - Type* t = expr->type(); - if (t->array_type() != NULL - || (t->points_to() != NULL - && t->points_to()->array_type() != NULL - && !t->points_to()->is_slice_type())) - { - if (get_index_type) - return Type::lookup_integer_type("int"); - else - return t->deref()->array_type()->element_type(); - } - else if (t->is_string_type()) - { - if (get_index_type) - return Type::lookup_integer_type("int"); - else - return Type::lookup_integer_type("int32"); - } - else if (t->map_type() != NULL) - { - if (get_index_type) - return t->map_type()->key_type(); - else - return t->map_type()->val_type(); - } - else if (t->channel_type() != NULL) - { - if (get_index_type) - return t->channel_type()->element_type(); - else - { - if (report_error) - error_at(this->location(), - "invalid definition of value variable for channel range"); - return Type::make_error_type(); - } - } - else - { - if (report_error) - error_at(this->location(), "invalid type for range clause"); - return Type::make_error_type(); - } -} - -// EXPR should be a channel. Return the channel's element type. - -Type* -Variable::type_from_chan_element(Expression* expr, bool report_error) const -{ - Type* t = expr->type(); - if (t->channel_type() != NULL) - return t->channel_type()->element_type(); - else - { - if (report_error) - error_at(this->location(), "expected channel"); - return Type::make_error_type(); - } -} - -// Return the type of the Variable. This may be called before -// Variable::determine_type is called, which means that we may need to -// get the type from the initializer. FIXME: If we combine lowering -// with type determination, then this should be unnecessary. - -Type* -Variable::type() -{ - // A variable in a type switch with a nil case will have the wrong - // type here. This gets fixed up in determine_type, below. - Type* type = this->type_; - Expression* init = this->init_; - if (this->is_type_switch_var_ - && this->type_->is_nil_constant_as_type()) - { - Type_guard_expression* tge = this->init_->type_guard_expression(); - go_assert(tge != NULL); - init = tge->expr(); - type = NULL; - } - - if (this->seen_) - { - if (this->type_ == NULL || !this->type_->is_error_type()) - { - error_at(this->location_, "variable initializer refers to itself"); - this->type_ = Type::make_error_type(); - } - return this->type_; - } - - this->seen_ = true; - - if (type != NULL) - ; - else if (this->type_from_init_tuple_) - type = this->type_from_tuple(init, false); - else if (this->type_from_range_index_ || this->type_from_range_value_) - type = this->type_from_range(init, this->type_from_range_index_, false); - else if (this->type_from_chan_element_) - type = this->type_from_chan_element(init, false); - else - { - go_assert(init != NULL); - type = init->type(); - go_assert(type != NULL); - - // Variables should not have abstract types. - if (type->is_abstract()) - type = type->make_non_abstract_type(); - - if (type->is_void_type()) - type = Type::make_error_type(); - } - - this->seen_ = false; - - return type; -} - -// Fetch the type from a const pointer, in which case it should have -// been set already. - -Type* -Variable::type() const -{ - go_assert(this->type_ != NULL); - return this->type_; -} - -// Set the type if necessary. - -void -Variable::determine_type() -{ - if (this->determined_type_) - return; - this->determined_type_ = true; - - if (this->preinit_ != NULL) - this->preinit_->determine_types(); - - // A variable in a type switch with a nil case will have the wrong - // type here. It will have an initializer which is a type guard. - // We want to initialize it to the value without the type guard, and - // use the type of that value as well. - if (this->is_type_switch_var_ && this->type_->is_nil_constant_as_type()) - { - Type_guard_expression* tge = this->init_->type_guard_expression(); - go_assert(tge != NULL); - this->type_ = NULL; - this->init_ = tge->expr(); - } - - if (this->init_ == NULL) - go_assert(this->type_ != NULL && !this->type_->is_abstract()); - else if (this->type_from_init_tuple_) - { - Expression *init = this->init_; - init->determine_type_no_context(); - this->type_ = this->type_from_tuple(init, true); - this->init_ = NULL; - } - else if (this->type_from_range_index_ || this->type_from_range_value_) - { - Expression* init = this->init_; - init->determine_type_no_context(); - this->type_ = this->type_from_range(init, this->type_from_range_index_, - true); - this->init_ = NULL; - } - else if (this->type_from_chan_element_) - { - Expression* init = this->init_; - init->determine_type_no_context(); - this->type_ = this->type_from_chan_element(init, true); - this->init_ = NULL; - } - else - { - Type_context context(this->type_, false); - this->init_->determine_type(&context); - if (this->type_ == NULL) - { - Type* type = this->init_->type(); - go_assert(type != NULL); - if (type->is_abstract()) - type = type->make_non_abstract_type(); - - if (type->is_void_type()) - { - error_at(this->location_, "variable has no type"); - type = Type::make_error_type(); - } - else if (type->is_nil_type()) - { - error_at(this->location_, "variable defined to nil type"); - type = Type::make_error_type(); - } - else if (type->is_call_multiple_result_type()) - { - error_at(this->location_, - "single variable set to multiple-value function call"); - type = Type::make_error_type(); - } - - this->type_ = type; - } - } -} - -// Export the variable - -void -Variable::export_var(Export* exp, const std::string& name) const -{ - go_assert(this->is_global_); - exp->write_c_string("var "); - exp->write_string(name); - exp->write_c_string(" "); - exp->write_type(this->type()); - exp->write_c_string(";\n"); -} - -// Import a variable. - -void -Variable::import_var(Import* imp, std::string* pname, Type** ptype) -{ - imp->require_c_string("var "); - *pname = imp->read_identifier(); - imp->require_c_string(" "); - *ptype = imp->read_type(); - imp->require_c_string(";\n"); -} - -// Convert a variable to the backend representation. - -Bvariable* -Variable::get_backend_variable(Gogo* gogo, Named_object* function, - const Package* package, const std::string& name) -{ - if (this->backend_ == NULL) - { - Backend* backend = gogo->backend(); - Type* type = this->type_; - if (type->is_error_type() - || (type->is_undefined() - && (!this->is_global_ || package == NULL))) - this->backend_ = backend->error_variable(); - else - { - bool is_parameter = this->is_parameter_; - if (this->is_receiver_ && type->points_to() == NULL) - is_parameter = false; - if (this->is_in_heap()) - { - is_parameter = false; - type = Type::make_pointer_type(type); - } - - std::string n = Gogo::unpack_hidden_name(name); - Btype* btype = type->get_backend(gogo); - - Bvariable* bvar; - if (this->is_global_) - bvar = backend->global_variable((package == NULL - ? gogo->package_name() - : package->package_name()), - (package == NULL - ? gogo->pkgpath_symbol() - : package->pkgpath_symbol()), - n, - btype, - package != NULL, - Gogo::is_hidden_name(name), - this->in_unique_section_, - this->location_); - else if (function == NULL) - { - go_assert(saw_errors()); - bvar = backend->error_variable(); - } - else - { - tree fndecl = function->func_value()->get_decl(); - Bfunction* bfunction = tree_to_function(fndecl); - bool is_address_taken = (this->is_non_escaping_address_taken_ - && !this->is_in_heap()); - if (is_parameter) - bvar = backend->parameter_variable(bfunction, n, btype, - is_address_taken, - this->location_); - else - bvar = backend->local_variable(bfunction, n, btype, - is_address_taken, - this->location_); - } - this->backend_ = bvar; - } - } - return this->backend_; -} - -// Class Result_variable. - -// Convert a result variable to the backend representation. - -Bvariable* -Result_variable::get_backend_variable(Gogo* gogo, Named_object* function, - const std::string& name) -{ - if (this->backend_ == NULL) - { - Backend* backend = gogo->backend(); - Type* type = this->type_; - if (type->is_error()) - this->backend_ = backend->error_variable(); - else - { - if (this->is_in_heap()) - type = Type::make_pointer_type(type); - Btype* btype = type->get_backend(gogo); - tree fndecl = function->func_value()->get_decl(); - Bfunction* bfunction = tree_to_function(fndecl); - std::string n = Gogo::unpack_hidden_name(name); - bool is_address_taken = (this->is_non_escaping_address_taken_ - && !this->is_in_heap()); - this->backend_ = backend->local_variable(bfunction, n, btype, - is_address_taken, - this->location_); - } - } - return this->backend_; -} - -// Class Named_constant. - -// Traverse the initializer expression. - -int -Named_constant::traverse_expression(Traverse* traverse) -{ - return Expression::traverse(&this->expr_, traverse); -} - -// Determine the type of the constant. - -void -Named_constant::determine_type() -{ - if (this->type_ != NULL) - { - Type_context context(this->type_, false); - this->expr_->determine_type(&context); - } - else - { - // A constant may have an abstract type. - Type_context context(NULL, true); - this->expr_->determine_type(&context); - this->type_ = this->expr_->type(); - go_assert(this->type_ != NULL); - } -} - -// Indicate that we found and reported an error for this constant. - -void -Named_constant::set_error() -{ - this->type_ = Type::make_error_type(); - this->expr_ = Expression::make_error(this->location_); -} - -// Export a constant. - -void -Named_constant::export_const(Export* exp, const std::string& name) const -{ - exp->write_c_string("const "); - exp->write_string(name); - exp->write_c_string(" "); - if (!this->type_->is_abstract()) - { - exp->write_type(this->type_); - exp->write_c_string(" "); - } - exp->write_c_string("= "); - this->expr()->export_expression(exp); - exp->write_c_string(";\n"); -} - -// Import a constant. - -void -Named_constant::import_const(Import* imp, std::string* pname, Type** ptype, - Expression** pexpr) -{ - imp->require_c_string("const "); - *pname = imp->read_identifier(); - imp->require_c_string(" "); - if (imp->peek_char() == '=') - *ptype = NULL; - else - { - *ptype = imp->read_type(); - imp->require_c_string(" "); - } - imp->require_c_string("= "); - *pexpr = Expression::import_expression(imp); - imp->require_c_string(";\n"); -} - -// Add a method. - -Named_object* -Type_declaration::add_method(const std::string& name, Function* function) -{ - Named_object* ret = Named_object::make_function(name, NULL, function); - this->methods_.push_back(ret); - return ret; -} - -// Add a method declaration. - -Named_object* -Type_declaration::add_method_declaration(const std::string& name, - Package* package, - Function_type* type, - Location location) -{ - Named_object* ret = Named_object::make_function_declaration(name, package, - type, location); - this->methods_.push_back(ret); - return ret; -} - -// Return whether any methods ere defined. - -bool -Type_declaration::has_methods() const -{ - return !this->methods_.empty(); -} - -// Define methods for the real type. - -void -Type_declaration::define_methods(Named_type* nt) -{ - for (std::vector<Named_object*>::const_iterator p = this->methods_.begin(); - p != this->methods_.end(); - ++p) - nt->add_existing_method(*p); -} - -// We are using the type. Return true if we should issue a warning. - -bool -Type_declaration::using_type() -{ - bool ret = !this->issued_warning_; - this->issued_warning_ = true; - return ret; -} - -// Class Unknown_name. - -// Set the real named object. - -void -Unknown_name::set_real_named_object(Named_object* no) -{ - go_assert(this->real_named_object_ == NULL); - go_assert(!no->is_unknown()); - this->real_named_object_ = no; -} - -// Class Named_object. - -Named_object::Named_object(const std::string& name, - const Package* package, - Classification classification) - : name_(name), package_(package), classification_(classification), - tree_(NULL) -{ - if (Gogo::is_sink_name(name)) - go_assert(classification == NAMED_OBJECT_SINK); -} - -// Make an unknown name. This is used by the parser. The name must -// be resolved later. Unknown names are only added in the current -// package. - -Named_object* -Named_object::make_unknown_name(const std::string& name, - Location location) -{ - Named_object* named_object = new Named_object(name, NULL, - NAMED_OBJECT_UNKNOWN); - Unknown_name* value = new Unknown_name(location); - named_object->u_.unknown_value = value; - return named_object; -} - -// Make a constant. - -Named_object* -Named_object::make_constant(const Typed_identifier& tid, - const Package* package, Expression* expr, - int iota_value) -{ - Named_object* named_object = new Named_object(tid.name(), package, - NAMED_OBJECT_CONST); - Named_constant* named_constant = new Named_constant(tid.type(), expr, - iota_value, - tid.location()); - named_object->u_.const_value = named_constant; - return named_object; -} - -// Make a named type. - -Named_object* -Named_object::make_type(const std::string& name, const Package* package, - Type* type, Location location) -{ - Named_object* named_object = new Named_object(name, package, - NAMED_OBJECT_TYPE); - Named_type* named_type = Type::make_named_type(named_object, type, location); - named_object->u_.type_value = named_type; - return named_object; -} - -// Make a type declaration. - -Named_object* -Named_object::make_type_declaration(const std::string& name, - const Package* package, - Location location) -{ - Named_object* named_object = new Named_object(name, package, - NAMED_OBJECT_TYPE_DECLARATION); - Type_declaration* type_declaration = new Type_declaration(location); - named_object->u_.type_declaration = type_declaration; - return named_object; -} - -// Make a variable. - -Named_object* -Named_object::make_variable(const std::string& name, const Package* package, - Variable* variable) -{ - Named_object* named_object = new Named_object(name, package, - NAMED_OBJECT_VAR); - named_object->u_.var_value = variable; - return named_object; -} - -// Make a result variable. - -Named_object* -Named_object::make_result_variable(const std::string& name, - Result_variable* result) -{ - Named_object* named_object = new Named_object(name, NULL, - NAMED_OBJECT_RESULT_VAR); - named_object->u_.result_var_value = result; - return named_object; -} - -// Make a sink. This is used for the special blank identifier _. - -Named_object* -Named_object::make_sink() -{ - return new Named_object("_", NULL, NAMED_OBJECT_SINK); -} - -// Make a named function. - -Named_object* -Named_object::make_function(const std::string& name, const Package* package, - Function* function) -{ - Named_object* named_object = new Named_object(name, package, - NAMED_OBJECT_FUNC); - named_object->u_.func_value = function; - return named_object; -} - -// Make a function declaration. - -Named_object* -Named_object::make_function_declaration(const std::string& name, - const Package* package, - Function_type* fntype, - Location location) -{ - Named_object* named_object = new Named_object(name, package, - NAMED_OBJECT_FUNC_DECLARATION); - Function_declaration *func_decl = new Function_declaration(fntype, location); - named_object->u_.func_declaration_value = func_decl; - return named_object; -} - -// Make a package. - -Named_object* -Named_object::make_package(const std::string& alias, Package* package) -{ - Named_object* named_object = new Named_object(alias, NULL, - NAMED_OBJECT_PACKAGE); - named_object->u_.package_value = package; - return named_object; -} - -// Return the name to use in an error message. - -std::string -Named_object::message_name() const -{ - if (this->package_ == NULL) - return Gogo::message_name(this->name_); - std::string ret; - if (this->package_->has_package_name()) - ret = this->package_->package_name(); - else - ret = this->package_->pkgpath(); - ret = Gogo::message_name(ret); - ret += '.'; - ret += Gogo::message_name(this->name_); - return ret; -} - -// Set the type when a declaration is defined. - -void -Named_object::set_type_value(Named_type* named_type) -{ - go_assert(this->classification_ == NAMED_OBJECT_TYPE_DECLARATION); - Type_declaration* td = this->u_.type_declaration; - td->define_methods(named_type); - unsigned int index; - Named_object* in_function = td->in_function(&index); - if (in_function != NULL) - named_type->set_in_function(in_function, index); - delete td; - this->classification_ = NAMED_OBJECT_TYPE; - this->u_.type_value = named_type; -} - -// Define a function which was previously declared. - -void -Named_object::set_function_value(Function* function) -{ - go_assert(this->classification_ == NAMED_OBJECT_FUNC_DECLARATION); - this->classification_ = NAMED_OBJECT_FUNC; - // FIXME: We should free the old value. - this->u_.func_value = function; -} - -// Declare an unknown object as a type declaration. - -void -Named_object::declare_as_type() -{ - go_assert(this->classification_ == NAMED_OBJECT_UNKNOWN); - Unknown_name* unk = this->u_.unknown_value; - this->classification_ = NAMED_OBJECT_TYPE_DECLARATION; - this->u_.type_declaration = new Type_declaration(unk->location()); - delete unk; -} - -// Return the location of a named object. - -Location -Named_object::location() const -{ - switch (this->classification_) - { - default: - case NAMED_OBJECT_UNINITIALIZED: - go_unreachable(); - - case NAMED_OBJECT_ERRONEOUS: - return Linemap::unknown_location(); - - case NAMED_OBJECT_UNKNOWN: - return this->unknown_value()->location(); - - case NAMED_OBJECT_CONST: - return this->const_value()->location(); - - case NAMED_OBJECT_TYPE: - return this->type_value()->location(); - - case NAMED_OBJECT_TYPE_DECLARATION: - return this->type_declaration_value()->location(); - - case NAMED_OBJECT_VAR: - return this->var_value()->location(); - - case NAMED_OBJECT_RESULT_VAR: - return this->result_var_value()->location(); - - case NAMED_OBJECT_SINK: - go_unreachable(); - - case NAMED_OBJECT_FUNC: - return this->func_value()->location(); - - case NAMED_OBJECT_FUNC_DECLARATION: - return this->func_declaration_value()->location(); - - case NAMED_OBJECT_PACKAGE: - return this->package_value()->location(); - } -} - -// Export a named object. - -void -Named_object::export_named_object(Export* exp) const -{ - switch (this->classification_) - { - default: - case NAMED_OBJECT_UNINITIALIZED: - case NAMED_OBJECT_UNKNOWN: - go_unreachable(); - - case NAMED_OBJECT_ERRONEOUS: - break; - - case NAMED_OBJECT_CONST: - this->const_value()->export_const(exp, this->name_); - break; - - case NAMED_OBJECT_TYPE: - this->type_value()->export_named_type(exp, this->name_); - break; - - case NAMED_OBJECT_TYPE_DECLARATION: - error_at(this->type_declaration_value()->location(), - "attempt to export %<%s%> which was declared but not defined", - this->message_name().c_str()); - break; - - case NAMED_OBJECT_FUNC_DECLARATION: - this->func_declaration_value()->export_func(exp, this->name_); - break; - - case NAMED_OBJECT_VAR: - this->var_value()->export_var(exp, this->name_); - break; - - case NAMED_OBJECT_RESULT_VAR: - case NAMED_OBJECT_SINK: - go_unreachable(); - - case NAMED_OBJECT_FUNC: - this->func_value()->export_func(exp, this->name_); - break; - } -} - -// Convert a variable to the backend representation. - -Bvariable* -Named_object::get_backend_variable(Gogo* gogo, Named_object* function) -{ - if (this->classification_ == NAMED_OBJECT_VAR) - return this->var_value()->get_backend_variable(gogo, function, - this->package_, this->name_); - else if (this->classification_ == NAMED_OBJECT_RESULT_VAR) - return this->result_var_value()->get_backend_variable(gogo, function, - this->name_); - else - go_unreachable(); -} - -// Class Bindings. - -Bindings::Bindings(Bindings* enclosing) - : enclosing_(enclosing), named_objects_(), bindings_() -{ -} - -// Clear imports. - -void -Bindings::clear_file_scope(Gogo* gogo) -{ - Contour::iterator p = this->bindings_.begin(); - while (p != this->bindings_.end()) - { - bool keep; - if (p->second->package() != NULL) - keep = false; - else if (p->second->is_package()) - keep = false; - else if (p->second->is_function() - && !p->second->func_value()->type()->is_method() - && Gogo::unpack_hidden_name(p->second->name()) == "init") - keep = false; - else - keep = true; - - if (keep) - ++p; - else - { - gogo->add_file_block_name(p->second->name(), p->second->location()); - p = this->bindings_.erase(p); - } - } -} - -// Look up a symbol. - -Named_object* -Bindings::lookup(const std::string& name) const -{ - Contour::const_iterator p = this->bindings_.find(name); - if (p != this->bindings_.end()) - return p->second->resolve(); - else if (this->enclosing_ != NULL) - return this->enclosing_->lookup(name); - else - return NULL; -} - -// Look up a symbol locally. - -Named_object* -Bindings::lookup_local(const std::string& name) const -{ - Contour::const_iterator p = this->bindings_.find(name); - if (p == this->bindings_.end()) - return NULL; - return p->second; -} - -// Remove an object from a set of bindings. This is used for a -// special case in thunks for functions which call recover. - -void -Bindings::remove_binding(Named_object* no) -{ - Contour::iterator pb = this->bindings_.find(no->name()); - go_assert(pb != this->bindings_.end()); - this->bindings_.erase(pb); - for (std::vector<Named_object*>::iterator pn = this->named_objects_.begin(); - pn != this->named_objects_.end(); - ++pn) - { - if (*pn == no) - { - this->named_objects_.erase(pn); - return; - } - } - go_unreachable(); -} - -// Add a method to the list of objects. This is not added to the -// lookup table. This is so that we have a single list of objects -// declared at the top level, which we walk through when it's time to -// convert to trees. - -void -Bindings::add_method(Named_object* method) -{ - this->named_objects_.push_back(method); -} - -// Add a generic Named_object to a Contour. - -Named_object* -Bindings::add_named_object_to_contour(Contour* contour, - Named_object* named_object) -{ - go_assert(named_object == named_object->resolve()); - const std::string& name(named_object->name()); - go_assert(!Gogo::is_sink_name(name)); - - std::pair<Contour::iterator, bool> ins = - contour->insert(std::make_pair(name, named_object)); - if (!ins.second) - { - // The name was already there. - if (named_object->package() != NULL - && ins.first->second->package() == named_object->package() - && (ins.first->second->classification() - == named_object->classification())) - { - // This is a second import of the same object. - return ins.first->second; - } - ins.first->second = this->new_definition(ins.first->second, - named_object); - return ins.first->second; - } - else - { - // Don't push declarations on the list. We push them on when - // and if we find the definitions. That way we genericize the - // functions in order. - if (!named_object->is_type_declaration() - && !named_object->is_function_declaration() - && !named_object->is_unknown()) - this->named_objects_.push_back(named_object); - return named_object; - } -} - -// We had an existing named object OLD_OBJECT, and we've seen a new -// one NEW_OBJECT with the same name. FIXME: This does not free the -// new object when we don't need it. - -Named_object* -Bindings::new_definition(Named_object* old_object, Named_object* new_object) -{ - if (new_object->is_erroneous() && !old_object->is_erroneous()) - return new_object; - - std::string reason; - switch (old_object->classification()) - { - default: - case Named_object::NAMED_OBJECT_UNINITIALIZED: - go_unreachable(); - - case Named_object::NAMED_OBJECT_ERRONEOUS: - return old_object; - - case Named_object::NAMED_OBJECT_UNKNOWN: - { - Named_object* real = old_object->unknown_value()->real_named_object(); - if (real != NULL) - return this->new_definition(real, new_object); - go_assert(!new_object->is_unknown()); - old_object->unknown_value()->set_real_named_object(new_object); - if (!new_object->is_type_declaration() - && !new_object->is_function_declaration()) - this->named_objects_.push_back(new_object); - return new_object; - } - - case Named_object::NAMED_OBJECT_CONST: - break; - - case Named_object::NAMED_OBJECT_TYPE: - if (new_object->is_type_declaration()) - return old_object; - break; - - case Named_object::NAMED_OBJECT_TYPE_DECLARATION: - if (new_object->is_type_declaration()) - return old_object; - if (new_object->is_type()) - { - old_object->set_type_value(new_object->type_value()); - new_object->type_value()->set_named_object(old_object); - this->named_objects_.push_back(old_object); - return old_object; - } - break; - - case Named_object::NAMED_OBJECT_VAR: - case Named_object::NAMED_OBJECT_RESULT_VAR: - // We have already given an error in the parser for cases where - // one parameter or result variable redeclares another one. - if ((new_object->is_variable() - && new_object->var_value()->is_parameter()) - || new_object->is_result_variable()) - return old_object; - break; - - case Named_object::NAMED_OBJECT_SINK: - go_unreachable(); - - case Named_object::NAMED_OBJECT_FUNC: - if (new_object->is_function_declaration()) - { - if (!new_object->func_declaration_value()->asm_name().empty()) - sorry("__asm__ for function definitions"); - Function_type* old_type = old_object->func_value()->type(); - Function_type* new_type = - new_object->func_declaration_value()->type(); - if (old_type->is_valid_redeclaration(new_type, &reason)) - return old_object; - } - break; - - case Named_object::NAMED_OBJECT_FUNC_DECLARATION: - { - Function_type* old_type = old_object->func_declaration_value()->type(); - if (new_object->is_function_declaration()) - { - Function_type* new_type = - new_object->func_declaration_value()->type(); - if (old_type->is_valid_redeclaration(new_type, &reason)) - return old_object; - } - if (new_object->is_function()) - { - Function_type* new_type = new_object->func_value()->type(); - if (old_type->is_valid_redeclaration(new_type, &reason)) - { - if (!old_object->func_declaration_value()->asm_name().empty()) - sorry("__asm__ for function definitions"); - old_object->set_function_value(new_object->func_value()); - this->named_objects_.push_back(old_object); - return old_object; - } - } - } - break; - - case Named_object::NAMED_OBJECT_PACKAGE: - break; - } - - std::string n = old_object->message_name(); - if (reason.empty()) - error_at(new_object->location(), "redefinition of %qs", n.c_str()); - else - error_at(new_object->location(), "redefinition of %qs: %s", n.c_str(), - reason.c_str()); - - inform(old_object->location(), "previous definition of %qs was here", - n.c_str()); - - return old_object; -} - -// Add a named type. - -Named_object* -Bindings::add_named_type(Named_type* named_type) -{ - return this->add_named_object(named_type->named_object()); -} - -// Add a function. - -Named_object* -Bindings::add_function(const std::string& name, const Package* package, - Function* function) -{ - return this->add_named_object(Named_object::make_function(name, package, - function)); -} - -// Add a function declaration. - -Named_object* -Bindings::add_function_declaration(const std::string& name, - const Package* package, - Function_type* type, - Location location) -{ - Named_object* no = Named_object::make_function_declaration(name, package, - type, location); - return this->add_named_object(no); -} - -// Define a type which was previously declared. - -void -Bindings::define_type(Named_object* no, Named_type* type) -{ - no->set_type_value(type); - this->named_objects_.push_back(no); -} - -// Mark all local variables as used. This is used for some types of -// parse error. - -void -Bindings::mark_locals_used() -{ - for (std::vector<Named_object*>::iterator p = this->named_objects_.begin(); - p != this->named_objects_.end(); - ++p) - if ((*p)->is_variable()) - (*p)->var_value()->set_is_used(); -} - -// Traverse bindings. - -int -Bindings::traverse(Traverse* traverse, bool is_global) -{ - unsigned int traverse_mask = traverse->traverse_mask(); - - // We don't use an iterator because we permit the traversal to add - // new global objects. - const unsigned int e_or_t = (Traverse::traverse_expressions - | Traverse::traverse_types); - const unsigned int e_or_t_or_s = (e_or_t - | Traverse::traverse_statements); - for (size_t i = 0; i < this->named_objects_.size(); ++i) - { - Named_object* p = this->named_objects_[i]; - int t = TRAVERSE_CONTINUE; - switch (p->classification()) - { - case Named_object::NAMED_OBJECT_CONST: - if ((traverse_mask & Traverse::traverse_constants) != 0) - t = traverse->constant(p, is_global); - if (t == TRAVERSE_CONTINUE - && (traverse_mask & e_or_t) != 0) - { - Type* tc = p->const_value()->type(); - if (tc != NULL - && Type::traverse(tc, traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - t = p->const_value()->traverse_expression(traverse); - } - break; - - case Named_object::NAMED_OBJECT_VAR: - case Named_object::NAMED_OBJECT_RESULT_VAR: - if ((traverse_mask & Traverse::traverse_variables) != 0) - t = traverse->variable(p); - if (t == TRAVERSE_CONTINUE - && (traverse_mask & e_or_t) != 0) - { - if (p->is_result_variable() - || p->var_value()->has_type()) - { - Type* tv = (p->is_variable() - ? p->var_value()->type() - : p->result_var_value()->type()); - if (tv != NULL - && Type::traverse(tv, traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - } - if (t == TRAVERSE_CONTINUE - && (traverse_mask & e_or_t_or_s) != 0 - && p->is_variable()) - t = p->var_value()->traverse_expression(traverse, traverse_mask); - break; - - case Named_object::NAMED_OBJECT_FUNC: - if ((traverse_mask & Traverse::traverse_functions) != 0) - t = traverse->function(p); - - if (t == TRAVERSE_CONTINUE - && (traverse_mask - & (Traverse::traverse_variables - | Traverse::traverse_constants - | Traverse::traverse_functions - | Traverse::traverse_blocks - | Traverse::traverse_statements - | Traverse::traverse_expressions - | Traverse::traverse_types)) != 0) - t = p->func_value()->traverse(traverse); - break; - - case Named_object::NAMED_OBJECT_PACKAGE: - // These are traversed in Gogo::traverse. - go_assert(is_global); - break; - - case Named_object::NAMED_OBJECT_TYPE: - if ((traverse_mask & e_or_t) != 0) - t = Type::traverse(p->type_value(), traverse); - break; - - case Named_object::NAMED_OBJECT_TYPE_DECLARATION: - case Named_object::NAMED_OBJECT_FUNC_DECLARATION: - case Named_object::NAMED_OBJECT_UNKNOWN: - case Named_object::NAMED_OBJECT_ERRONEOUS: - break; - - case Named_object::NAMED_OBJECT_SINK: - default: - go_unreachable(); - } - - if (t == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - - // If we need to traverse types, check the function declarations, - // which have types. Also check any methods of a type declaration. - if ((traverse_mask & e_or_t) != 0) - { - for (Bindings::const_declarations_iterator p = - this->begin_declarations(); - p != this->end_declarations(); - ++p) - { - if (p->second->is_function_declaration()) - { - if (Type::traverse(p->second->func_declaration_value()->type(), - traverse) - == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - else if (p->second->is_type_declaration()) - { - const std::vector<Named_object*>* methods = - p->second->type_declaration_value()->methods(); - for (std::vector<Named_object*>::const_iterator pm = - methods->begin(); - pm != methods->end(); - pm++) - { - Named_object* no = *pm; - Type *t; - if (no->is_function()) - t = no->func_value()->type(); - else if (no->is_function_declaration()) - t = no->func_declaration_value()->type(); - else - continue; - if (Type::traverse(t, traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - } - } - } - - return TRAVERSE_CONTINUE; -} - -// Class Label. - -// Clear any references to this label. - -void -Label::clear_refs() -{ - for (std::vector<Bindings_snapshot*>::iterator p = this->refs_.begin(); - p != this->refs_.end(); - ++p) - delete *p; - this->refs_.clear(); -} - -// Get the backend representation for a label. - -Blabel* -Label::get_backend_label(Translate_context* context) -{ - if (this->blabel_ == NULL) - { - Function* function = context->function()->func_value(); - tree fndecl = function->get_decl(); - Bfunction* bfunction = tree_to_function(fndecl); - this->blabel_ = context->backend()->label(bfunction, this->name_, - this->location_); - } - return this->blabel_; -} - -// Return an expression for the address of this label. - -Bexpression* -Label::get_addr(Translate_context* context, Location location) -{ - Blabel* label = this->get_backend_label(context); - return context->backend()->label_address(label, location); -} - -// Class Unnamed_label. - -// Get the backend representation for an unnamed label. - -Blabel* -Unnamed_label::get_blabel(Translate_context* context) -{ - if (this->blabel_ == NULL) - { - Function* function = context->function()->func_value(); - tree fndecl = function->get_decl(); - Bfunction* bfunction = tree_to_function(fndecl); - this->blabel_ = context->backend()->label(bfunction, "", - this->location_); - } - return this->blabel_; -} - -// Return a statement which defines this unnamed label. - -Bstatement* -Unnamed_label::get_definition(Translate_context* context) -{ - Blabel* blabel = this->get_blabel(context); - return context->backend()->label_definition_statement(blabel); -} - -// Return a goto statement to this unnamed label. - -Bstatement* -Unnamed_label::get_goto(Translate_context* context, Location location) -{ - Blabel* blabel = this->get_blabel(context); - return context->backend()->goto_statement(blabel, location); -} - -// Class Package. - -Package::Package(const std::string& pkgpath, Location location) - : pkgpath_(pkgpath), pkgpath_symbol_(Gogo::pkgpath_for_symbol(pkgpath)), - package_name_(), bindings_(new Bindings(NULL)), priority_(0), - location_(location), used_(false), is_imported_(false), - uses_sink_alias_(false) -{ - go_assert(!pkgpath.empty()); - -} - -// Set the package name. - -void -Package::set_package_name(const std::string& package_name, Location location) -{ - go_assert(!package_name.empty()); - if (this->package_name_.empty()) - this->package_name_ = package_name; - else if (this->package_name_ != package_name) - error_at(location, - "saw two different packages with the same package path %s: %s, %s", - this->pkgpath_.c_str(), this->package_name_.c_str(), - package_name.c_str()); -} - -// Set the priority. We may see multiple priorities for an imported -// package; we want to use the largest one. - -void -Package::set_priority(int priority) -{ - if (priority > this->priority_) - this->priority_ = priority; -} - -// Determine types of constants. Everything else in a package -// (variables, function declarations) should already have a fixed -// type. Constants may have abstract types. - -void -Package::determine_types() -{ - Bindings* bindings = this->bindings_; - for (Bindings::const_definitions_iterator p = bindings->begin_definitions(); - p != bindings->end_definitions(); - ++p) - { - if ((*p)->is_const()) - (*p)->const_value()->determine_type(); - } -} - -// Class Traverse. - -// Destructor. - -Traverse::~Traverse() -{ - if (this->types_seen_ != NULL) - delete this->types_seen_; - if (this->expressions_seen_ != NULL) - delete this->expressions_seen_; -} - -// Record that we are looking at a type, and return true if we have -// already seen it. - -bool -Traverse::remember_type(const Type* type) -{ - if (type->is_error_type()) - return true; - go_assert((this->traverse_mask() & traverse_types) != 0 - || (this->traverse_mask() & traverse_expressions) != 0); - // We mostly only have to remember named types. But it turns out - // that an interface type can refer to itself without using a name - // by relying on interface inheritance, as in - // type I interface { F() interface{I} } - if (type->classification() != Type::TYPE_NAMED - && type->classification() != Type::TYPE_INTERFACE) - return false; - if (this->types_seen_ == NULL) - this->types_seen_ = new Types_seen(); - std::pair<Types_seen::iterator, bool> ins = this->types_seen_->insert(type); - return !ins.second; -} - -// Record that we are looking at an expression, and return true if we -// have already seen it. - -bool -Traverse::remember_expression(const Expression* expression) -{ - go_assert((this->traverse_mask() & traverse_types) != 0 - || (this->traverse_mask() & traverse_expressions) != 0); - if (this->expressions_seen_ == NULL) - this->expressions_seen_ = new Expressions_seen(); - std::pair<Expressions_seen::iterator, bool> ins = - this->expressions_seen_->insert(expression); - return !ins.second; -} - -// The default versions of these functions should never be called: the -// traversal mask indicates which functions may be called. - -int -Traverse::variable(Named_object*) -{ - go_unreachable(); -} - -int -Traverse::constant(Named_object*, bool) -{ - go_unreachable(); -} - -int -Traverse::function(Named_object*) -{ - go_unreachable(); -} - -int -Traverse::block(Block*) -{ - go_unreachable(); -} - -int -Traverse::statement(Block*, size_t*, Statement*) -{ - go_unreachable(); -} - -int -Traverse::expression(Expression**) -{ - go_unreachable(); -} - -int -Traverse::type(Type*) -{ - go_unreachable(); -} - -// Class Statement_inserter. - -void -Statement_inserter::insert(Statement* s) -{ - if (this->block_ != NULL) - { - go_assert(this->pindex_ != NULL); - this->block_->insert_statement_before(*this->pindex_, s); - ++*this->pindex_; - } - else if (this->var_ != NULL) - this->var_->add_preinit_statement(this->gogo_, s); - else - go_assert(saw_errors()); -} diff --git a/gcc-4.8.1/gcc/go/gofrontend/gogo.h b/gcc-4.8.1/gcc/go/gofrontend/gogo.h deleted file mode 100644 index f96ffcdfd..000000000 --- a/gcc-4.8.1/gcc/go/gofrontend/gogo.h +++ /dev/null @@ -1,2939 +0,0 @@ -// gogo.h -- Go frontend parsed representation. -*- C++ -*- - -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#ifndef GO_GOGO_H -#define GO_GOGO_H - -#include "go-linemap.h" - -class Traverse; -class Statement_inserter; -class Type; -class Type_hash_identical; -class Type_equal; -class Type_identical; -class Typed_identifier; -class Typed_identifier_list; -class Function_type; -class Expression; -class Statement; -class Temporary_statement; -class Block; -class Function; -class Bindings; -class Bindings_snapshot; -class Package; -class Variable; -class Pointer_type; -class Struct_type; -class Struct_field; -class Struct_field_list; -class Array_type; -class Map_type; -class Channel_type; -class Interface_type; -class Named_type; -class Forward_declaration_type; -class Named_object; -class Label; -class Translate_context; -class Backend; -class Export; -class Import; -class Bexpression; -class Bstatement; -class Bblock; -class Bvariable; -class Blabel; - -// This file declares the basic classes used to hold the internal -// representation of Go which is built by the parser. - -// An initialization function for an imported package. This is a -// magic function which initializes variables and runs the "init" -// function. - -class Import_init -{ - public: - Import_init(const std::string& package_name, const std::string& init_name, - int priority) - : package_name_(package_name), init_name_(init_name), priority_(priority) - { } - - // The name of the package being imported. - const std::string& - package_name() const - { return this->package_name_; } - - // The name of the package's init function. - const std::string& - init_name() const - { return this->init_name_; } - - // The priority of the initialization function. Functions with a - // lower priority number must be run first. - int - priority() const - { return this->priority_; } - - private: - // The name of the package being imported. - std::string package_name_; - // The name of the package's init function. - std::string init_name_; - // The priority. - int priority_; -}; - -// For sorting purposes. - -inline bool -operator<(const Import_init& i1, const Import_init& i2) -{ - if (i1.priority() < i2.priority()) - return true; - if (i1.priority() > i2.priority()) - return false; - if (i1.package_name() != i2.package_name()) - return i1.package_name() < i2.package_name(); - return i1.init_name() < i2.init_name(); -} - -// The holder for the internal representation of the entire -// compilation unit. - -class Gogo -{ - public: - // Create the IR, passing in the sizes of the types "int" and - // "uintptr" in bits. - Gogo(Backend* backend, Linemap *linemap, int int_type_size, int pointer_size); - - // Get the backend generator. - Backend* - backend() - { return this->backend_; } - - // Get the Location generator. - Linemap* - linemap() - { return this->linemap_; } - - // Get the package name. - const std::string& - package_name() const; - - // Set the package name. - void - set_package_name(const std::string&, Location); - - // Return whether this is the "main" package. - bool - is_main_package() const; - - // If necessary, adjust the name to use for a hidden symbol. We add - // the package name, so that hidden symbols in different packages do - // not collide. - std::string - pack_hidden_name(const std::string& name, bool is_exported) const - { - return (is_exported - ? name - : '.' + this->pkgpath() + '.' + name); - } - - // Unpack a name which may have been hidden. Returns the - // user-visible name of the object. - static std::string - unpack_hidden_name(const std::string& name) - { return name[0] != '.' ? name : name.substr(name.rfind('.') + 1); } - - // Return whether a possibly packed name is hidden. - static bool - is_hidden_name(const std::string& name) - { return name[0] == '.'; } - - // Return the package path of a hidden name. - static std::string - hidden_name_pkgpath(const std::string& name) - { - go_assert(Gogo::is_hidden_name(name)); - return name.substr(1, name.rfind('.') - 1); - } - - // Given a name which may or may not have been hidden, return the - // name to use in an error message. - static std::string - message_name(const std::string& name); - - // Return whether a name is the blank identifier _. - static bool - is_sink_name(const std::string& name) - { - return (name[0] == '.' - && name[name.length() - 1] == '_' - && name[name.length() - 2] == '.'); - } - - // Convert a pkgpath into a string suitable for a symbol - static std::string - pkgpath_for_symbol(const std::string& pkgpath); - - // Return the package path to use for reflect.Type.PkgPath. - const std::string& - pkgpath() const; - - // Return the package path to use for a symbol name. - const std::string& - pkgpath_symbol() const; - - // Set the package path from a command line option. - void - set_pkgpath(const std::string&); - - // Set the prefix from a command line option. - void - set_prefix(const std::string&); - - // Return whether pkgpath was set from a command line option. - bool - pkgpath_from_option() const - { return this->pkgpath_from_option_; } - - // Return the relative import path as set from the command line. - // Returns an empty string if it was not set. - const std::string& - relative_import_path() const - { return this->relative_import_path_; } - - // Set the relative import path from a command line option. - void - set_relative_import_path(const std::string& s) - {this->relative_import_path_ = s; } - - // Return the priority to use for the package we are compiling. - // This is two more than the largest priority of any package we - // import. - int - package_priority() const; - - // Import a package. FILENAME is the file name argument, LOCAL_NAME - // is the local name to give to the package. If LOCAL_NAME is empty - // the declarations are added to the global scope. - void - import_package(const std::string& filename, const std::string& local_name, - bool is_local_name_exported, Location); - - // Whether we are the global binding level. - bool - in_global_scope() const; - - // Look up a name in the current binding contours. - Named_object* - lookup(const std::string&, Named_object** pfunction) const; - - // Look up a name in the current block. - Named_object* - lookup_in_block(const std::string&) const; - - // Look up a name in the global namespace--the universal scope. - Named_object* - lookup_global(const char*) const; - - // Add a new imported package. REAL_NAME is the real name of the - // package. ALIAS is the alias of the package; this may be the same - // as REAL_NAME. This sets *PADD_TO_GLOBALS if symbols added to - // this package should be added to the global namespace; this is - // true if the alias is ".". LOCATION is the location of the import - // statement. This returns the new package, or NULL on error. - Package* - add_imported_package(const std::string& real_name, const std::string& alias, - bool is_alias_exported, - const std::string& pkgpath, - Location location, - bool* padd_to_globals); - - // Register a package. This package may or may not be imported. - // This returns the Package structure for the package, creating if - // it necessary. - Package* - register_package(const std::string& pkgpath, Location); - - // Start compiling a function. ADD_METHOD_TO_TYPE is true if a - // method function should be added to the type of its receiver. - Named_object* - start_function(const std::string& name, Function_type* type, - bool add_method_to_type, Location); - - // Finish compiling a function. - void - finish_function(Location); - - // Return the current function. - Named_object* - current_function() const; - - // Return the current block. - Block* - current_block(); - - // Start a new block. This is not initially associated with a - // function. - void - start_block(Location); - - // Finish the current block and return it. - Block* - finish_block(Location); - - // Declare an erroneous name. This is used to avoid knock-on errors - // after a parsing error. - Named_object* - add_erroneous_name(const std::string& name); - - // Declare an unknown name. This is used while parsing. The name - // must be resolved by the end of the parse. Unknown names are - // always added at the package level. - Named_object* - add_unknown_name(const std::string& name, Location); - - // Declare a function. - Named_object* - declare_function(const std::string&, Function_type*, Location); - - // Declare a function at the package level. This is used for - // functions generated for a type. - Named_object* - declare_package_function(const std::string&, Function_type*, Location); - - // Add a label. - Label* - add_label_definition(const std::string&, Location); - - // Add a label reference. ISSUE_GOTO_ERRORS is true if we should - // report errors for a goto from the current location to the label - // location. - Label* - add_label_reference(const std::string&, Location, - bool issue_goto_errors); - - // Return a snapshot of the current binding state. - Bindings_snapshot* - bindings_snapshot(Location); - - // Add a statement to the current block. - void - add_statement(Statement*); - - // Add a block to the current block. - void - add_block(Block*, Location); - - // Add a constant. - Named_object* - add_constant(const Typed_identifier&, Expression*, int iota_value); - - // Add a type. - void - add_type(const std::string&, Type*, Location); - - // Add a named type. This is used for builtin types, and to add an - // imported type to the global scope. - void - add_named_type(Named_type*); - - // Declare a type. - Named_object* - declare_type(const std::string&, Location); - - // Declare a type at the package level. This is used when the - // parser sees an unknown name where a type name is required. - Named_object* - declare_package_type(const std::string&, Location); - - // Define a type which was already declared. - void - define_type(Named_object*, Named_type*); - - // Add a variable. - Named_object* - add_variable(const std::string&, Variable*); - - // Add a sink--a reference to the blank identifier _. - Named_object* - add_sink(); - - // Add a type which needs to be verified. This is used for sink - // types, just to give appropriate error messages. - void - add_type_to_verify(Type* type); - - // Add a named object to the current namespace. This is used for - // import . "package". - void - add_named_object(Named_object*); - - // Add an identifier to the list of names seen in the file block. - void - add_file_block_name(const std::string& name, Location location) - { this->file_block_names_[name] = location; } - - // Mark all local variables in current bindings as used. This is - // used when there is a parse error to avoid useless errors. - void - mark_locals_used(); - - // Return a name to use for a thunk function. A thunk function is - // one we create during the compilation, for a go statement or a - // defer statement or a method expression. - static std::string - thunk_name(); - - // Return whether an object is a thunk. - static bool - is_thunk(const Named_object*); - - // Note that we've seen an interface type. This is used to build - // all required interface method tables. - void - record_interface_type(Interface_type*); - - // Note that we need an initialization function. - void - set_need_init_fn() - { this->need_init_fn_ = true; } - - // Clear out all names in file scope. This is called when we start - // parsing a new file. - void - clear_file_scope(); - - // Record that VAR1 must be initialized after VAR2. This is used - // when VAR2 does not appear in VAR1's INIT or PREINIT. - void - record_var_depends_on(Variable* var1, Named_object* var2) - { - go_assert(this->var_deps_.find(var1) == this->var_deps_.end()); - this->var_deps_[var1] = var2; - } - - // Return the variable that VAR depends on, or NULL if none. - Named_object* - var_depends_on(Variable* var) const - { - Var_deps::const_iterator p = this->var_deps_.find(var); - return p != this->var_deps_.end() ? p->second : NULL; - } - - // Queue up a type-specific function to be written out. This is - // used when a type-specific function is needed when not at the top - // level. - void - queue_specific_type_function(Type* type, Named_type* name, - const std::string& hash_name, - Function_type* hash_fntype, - const std::string& equal_name, - Function_type* equal_fntype); - - // Write out queued specific type functions. - void - write_specific_type_functions(); - - // Whether we are done writing out specific type functions. - bool - specific_type_functions_are_written() const - { return this->specific_type_functions_are_written_; } - - // Traverse the tree. See the Traverse class. - void - traverse(Traverse*); - - // Define the predeclared global names. - void - define_global_names(); - - // Verify and complete all types. - void - verify_types(); - - // Lower the parse tree. - void - lower_parse_tree(); - - // Lower all the statements in a block. - void - lower_block(Named_object* function, Block*); - - // Lower an expression. - void - lower_expression(Named_object* function, Statement_inserter*, Expression**); - - // Lower a constant. - void - lower_constant(Named_object*); - - // Finalize the method lists and build stub methods for named types. - void - finalize_methods(); - - // Work out the types to use for unspecified variables and - // constants. - void - determine_types(); - - // Type check the program. - void - check_types(); - - // Check the types in a single block. This is used for complicated - // go statements. - void - check_types_in_block(Block*); - - // Check for return statements. - void - check_return_statements(); - - // Do all exports. - void - do_exports(); - - // Add an import control function for an imported package to the - // list. - void - add_import_init_fn(const std::string& package_name, - const std::string& init_name, int prio); - - // Turn short-cut operators (&&, ||) into explicit if statements. - void - remove_shortcuts(); - - // Use temporary variables to force order of evaluation. - void - order_evaluations(); - - // Build thunks for functions which call recover. - void - build_recover_thunks(); - - // Simplify statements which might use thunks: go and defer - // statements. - void - simplify_thunk_statements(); - - // Dump AST if -fgo-dump-ast is set - void - dump_ast(const char* basename); - - // Convert named types to the backend representation. - void - convert_named_types(); - - // Convert named types in a list of bindings. - void - convert_named_types_in_bindings(Bindings*); - - // True if named types have been converted to the backend - // representation. - bool - named_types_are_converted() const - { return this->named_types_are_converted_; } - - // Write out the global values. - void - write_globals(); - - // Create trees for implicit builtin functions. - void - define_builtin_function_trees(); - - // Build a call to a builtin function. PDECL should point to a NULL - // initialized static pointer which will hold the fndecl. NAME is - // the name of the function. NARGS is the number of arguments. - // RETTYPE is the return type. It is followed by NARGS pairs of - // type and argument (both trees). - static tree - call_builtin(tree* pdecl, Location, const char* name, int nargs, - tree rettype, ...); - - // Build a call to the runtime error function. - tree - runtime_error(int code, Location); - - // Build a builtin struct with a list of fields. - static tree - builtin_struct(tree* ptype, const char* struct_name, tree struct_type, - int nfields, ...); - - // Mark a function declaration as a builtin library function. - static void - mark_fndecl_as_builtin_library(tree fndecl); - - // Build a constructor for a slice. SLICE_TYPE_TREE is the type of - // the slice. VALUES points to the values. COUNT is the size, - // CAPACITY is the capacity. If CAPACITY is NULL, it is set to - // COUNT. - static tree - slice_constructor(tree slice_type_tree, tree values, tree count, - tree capacity); - - // Build required interface method tables. - void - build_interface_method_tables(); - - // Build an interface method table for a type: a list of function - // pointers, one for each interface method. This returns a decl. - tree - interface_method_table_for_type(const Interface_type*, Type*, - bool is_pointer); - - // Return a tree which allocate SIZE bytes to hold values of type - // TYPE. - tree - allocate_memory(Type *type, tree size, Location); - - // Return a type to use for pointer to const char. - static tree - const_char_pointer_type_tree(); - - // Build a string constant with the right type. - static tree - string_constant_tree(const std::string&); - - // Build a Go string constant. This returns a pointer to the - // constant. - tree - go_string_constant_tree(const std::string&); - - // Receive a value from a channel. - static tree - receive_from_channel(tree type_tree, tree type_descriptor_tree, tree channel, - Location); - - // Make a trampoline which calls FNADDR passing CLOSURE. - tree - make_trampoline(tree fnaddr, tree closure, Location); - - private: - // During parsing, we keep a stack of functions. Each function on - // the stack is one that we are currently parsing. For each - // function, we keep track of the current stack of blocks. - struct Open_function - { - // The function. - Named_object* function; - // The stack of active blocks in the function. - std::vector<Block*> blocks; - }; - - // The stack of functions. - typedef std::vector<Open_function> Open_functions; - - // Set up the built-in unsafe package. - void - import_unsafe(const std::string&, bool is_exported, Location); - - // Return the current binding contour. - Bindings* - current_bindings(); - - const Bindings* - current_bindings() const; - - // Get the name of the magic initialization function. - const std::string& - get_init_fn_name(); - - // Get the decl for the magic initialization function. - tree - initialization_function_decl(); - - // Write the magic initialization function. - void - write_initialization_function(tree fndecl, tree init_stmt_list); - - // Initialize imported packages. - void - init_imports(tree*); - - // Register variables with the garbage collector. - void - register_gc_vars(const std::vector<Named_object*>&, tree*); - - // Build a pointer to a Go string constant. This returns a pointer - // to the pointer. - tree - ptr_go_string_constant_tree(const std::string&); - - // Return the type of a trampoline. - static tree - trampoline_type_tree(); - - // Type used to map import names to packages. - typedef std::map<std::string, Package*> Imports; - - // Type used to map package names to packages. - typedef std::map<std::string, Package*> Packages; - - // Type used to map variables to the function calls that set them. - // This is used for initialization dependency analysis. - typedef std::map<Variable*, Named_object*> Var_deps; - - // Type used to map identifiers in the file block to the location - // where they were defined. - typedef Unordered_map(std::string, Location) File_block_names; - - // Type used to queue writing a type specific function. - struct Specific_type_function - { - Type* type; - Named_type* name; - std::string hash_name; - Function_type* hash_fntype; - std::string equal_name; - Function_type* equal_fntype; - - Specific_type_function(Type* atype, Named_type* aname, - const std::string& ahash_name, - Function_type* ahash_fntype, - const std::string& aequal_name, - Function_type* aequal_fntype) - : type(atype), name(aname), hash_name(ahash_name), - hash_fntype(ahash_fntype), equal_name(aequal_name), - equal_fntype(aequal_fntype) - { } - }; - - // The backend generator. - Backend* backend_; - // The object used to keep track of file names and line numbers. - Linemap* linemap_; - // The package we are compiling. - Package* package_; - // The list of currently open functions during parsing. - Open_functions functions_; - // The global binding contour. This includes the builtin functions - // and the package we are compiling. - Bindings* globals_; - // The list of names we have seen in the file block. - File_block_names file_block_names_; - // Mapping from import file names to packages. - Imports imports_; - // Whether the magic unsafe package was imported. - bool imported_unsafe_; - // Mapping from package names we have seen to packages. This does - // not include the package we are compiling. - Packages packages_; - // The functions named "init", if there are any. - std::vector<Named_object*> init_functions_; - // A mapping from variables to the function calls that initialize - // them, if it is not stored in the variable's init or preinit. - // This is used for dependency analysis. - Var_deps var_deps_; - // Whether we need a magic initialization function. - bool need_init_fn_; - // The name of the magic initialization function. - std::string init_fn_name_; - // A list of import control variables for packages that we import. - std::set<Import_init> imported_init_fns_; - // The package path used for reflection data. - std::string pkgpath_; - // The package path to use for a symbol name. - std::string pkgpath_symbol_; - // The prefix to use for symbols, from the -fgo-prefix option. - std::string prefix_; - // Whether pkgpath_ has been set. - bool pkgpath_set_; - // Whether an explicit package path was set by -fgo-pkgpath. - bool pkgpath_from_option_; - // Whether an explicit prefix was set by -fgo-prefix. - bool prefix_from_option_; - // The relative import path, from the -fgo-relative-import-path - // option. - std::string relative_import_path_; - // A list of types to verify. - std::vector<Type*> verify_types_; - // A list of interface types defined while parsing. - std::vector<Interface_type*> interface_types_; - // Type specific functions to write out. - std::vector<Specific_type_function*> specific_type_functions_; - // Whether we are done writing out specific type functions. - bool specific_type_functions_are_written_; - // Whether named types have been converted. - bool named_types_are_converted_; -}; - -// A block of statements. - -class Block -{ - public: - Block(Block* enclosing, Location); - - // Return the enclosing block. - const Block* - enclosing() const - { return this->enclosing_; } - - // Return the bindings of the block. - Bindings* - bindings() - { return this->bindings_; } - - const Bindings* - bindings() const - { return this->bindings_; } - - // Look at the block's statements. - const std::vector<Statement*>* - statements() const - { return &this->statements_; } - - // Return the start location. This is normally the location of the - // left curly brace which starts the block. - Location - start_location() const - { return this->start_location_; } - - // Return the end location. This is normally the location of the - // right curly brace which ends the block. - Location - end_location() const - { return this->end_location_; } - - // Add a statement to the block. - void - add_statement(Statement*); - - // Add a statement to the front of the block. - void - add_statement_at_front(Statement*); - - // Replace a statement in a block. - void - replace_statement(size_t index, Statement*); - - // Add a Statement before statement number INDEX. - void - insert_statement_before(size_t index, Statement*); - - // Add a Statement after statement number INDEX. - void - insert_statement_after(size_t index, Statement*); - - // Set the end location of the block. - void - set_end_location(Location location) - { this->end_location_ = location; } - - // Traverse the tree. - int - traverse(Traverse*); - - // Set final types for unspecified variables and constants. - void - determine_types(); - - // Return true if execution of this block may fall through to the - // next block. - bool - may_fall_through() const; - - // Convert the block to the backend representation. - Bblock* - get_backend(Translate_context*); - - // Iterate over statements. - - typedef std::vector<Statement*>::iterator iterator; - - iterator - begin() - { return this->statements_.begin(); } - - iterator - end() - { return this->statements_.end(); } - - private: - // Enclosing block. - Block* enclosing_; - // Statements in the block. - std::vector<Statement*> statements_; - // Binding contour. - Bindings* bindings_; - // Location of start of block. - Location start_location_; - // Location of end of block. - Location end_location_; -}; - -// A function. - -class Function -{ - public: - Function(Function_type* type, Function*, Block*, Location); - - // Return the function's type. - Function_type* - type() const - { return this->type_; } - - // Return the enclosing function if there is one. - Function* - enclosing() - { return this->enclosing_; } - - // Set the enclosing function. This is used when building thunks - // for functions which call recover. - void - set_enclosing(Function* enclosing) - { - go_assert(this->enclosing_ == NULL); - this->enclosing_ = enclosing; - } - - // The result variables. - typedef std::vector<Named_object*> Results; - - // Create the result variables in the outer block. - void - create_result_variables(Gogo*); - - // Update the named result variables when cloning a function which - // calls recover. - void - update_result_variables(); - - // Return the result variables. - Results* - result_variables() - { return this->results_; } - - // Whether the result variables have names. - bool - results_are_named() const - { return this->results_are_named_; } - - // Whether this method should not be included in the type - // descriptor. - bool - nointerface() const - { - go_assert(this->is_method()); - return this->nointerface_; - } - - // Record that this method should not be included in the type - // descriptor. - void - set_nointerface() - { - go_assert(this->is_method()); - this->nointerface_ = true; - } - - // Add a new field to the closure variable. - void - add_closure_field(Named_object* var, Location loc) - { this->closure_fields_.push_back(std::make_pair(var, loc)); } - - // Whether this function needs a closure. - bool - needs_closure() const - { return !this->closure_fields_.empty(); } - - // Return the closure variable, creating it if necessary. This is - // passed to the function as a static chain parameter. - Named_object* - closure_var(); - - // Set the closure variable. This is used when building thunks for - // functions which call recover. - void - set_closure_var(Named_object* v) - { - go_assert(this->closure_var_ == NULL); - this->closure_var_ = v; - } - - // Return the variable for a reference to field INDEX in the closure - // variable. - Named_object* - enclosing_var(unsigned int index) - { - go_assert(index < this->closure_fields_.size()); - return closure_fields_[index].first; - } - - // Set the type of the closure variable if there is one. - void - set_closure_type(); - - // Get the block of statements associated with the function. - Block* - block() const - { return this->block_; } - - // Get the location of the start of the function. - Location - location() const - { return this->location_; } - - // Return whether this function is actually a method. - bool - is_method() const; - - // Add a label definition to the function. - Label* - add_label_definition(Gogo*, const std::string& label_name, Location); - - // Add a label reference to a function. ISSUE_GOTO_ERRORS is true - // if we should report errors for a goto from the current location - // to the label location. - Label* - add_label_reference(Gogo*, const std::string& label_name, - Location, bool issue_goto_errors); - - // Warn about labels that are defined but not used. - void - check_labels() const; - - // Note that a new local type has been added. Return its index. - unsigned int - new_local_type_index() - { return this->local_type_count_++; } - - // Whether this function calls the predeclared recover function. - bool - calls_recover() const - { return this->calls_recover_; } - - // Record that this function calls the predeclared recover function. - // This is set during the lowering pass. - void - set_calls_recover() - { this->calls_recover_ = true; } - - // Whether this is a recover thunk function. - bool - is_recover_thunk() const - { return this->is_recover_thunk_; } - - // Record that this is a thunk built for a function which calls - // recover. - void - set_is_recover_thunk() - { this->is_recover_thunk_ = true; } - - // Whether this function already has a recover thunk. - bool - has_recover_thunk() const - { return this->has_recover_thunk_; } - - // Record that this function already has a recover thunk. - void - set_has_recover_thunk() - { this->has_recover_thunk_ = true; } - - // Mark the function as going into a unique section. - void - set_in_unique_section() - { this->in_unique_section_ = true; } - - // Swap with another function. Used only for the thunk which calls - // recover. - void - swap_for_recover(Function *); - - // Traverse the tree. - int - traverse(Traverse*); - - // Determine types in the function. - void - determine_types(); - - // Return the function's decl given an identifier. - tree - get_or_make_decl(Gogo*, Named_object*, tree id); - - // Return the function's decl after it has been built. - tree - get_decl() const - { - go_assert(this->fndecl_ != NULL); - return this->fndecl_; - } - - // Set the function decl to hold a tree of the function code. - void - build_tree(Gogo*, Named_object*); - - // Get the value to return when not explicitly specified. May also - // add statements to execute first to STMT_LIST. - tree - return_value(Gogo*, Named_object*, Location, tree* stmt_list) const; - - // Get a tree for the variable holding the defer stack. - Expression* - defer_stack(Location); - - // Export the function. - void - export_func(Export*, const std::string& name) const; - - // Export a function with a type. - static void - export_func_with_type(Export*, const std::string& name, - const Function_type*); - - // Import a function. - static void - import_func(Import*, std::string* pname, Typed_identifier** receiver, - Typed_identifier_list** pparameters, - Typed_identifier_list** presults, bool* is_varargs); - - private: - // Type for mapping from label names to Label objects. - typedef Unordered_map(std::string, Label*) Labels; - - tree - make_receiver_parm_decl(Gogo*, Named_object*, tree); - - tree - copy_parm_to_heap(Gogo*, Named_object*, tree); - - void - build_defer_wrapper(Gogo*, Named_object*, tree*, tree*); - - typedef std::vector<std::pair<Named_object*, - Location> > Closure_fields; - - // The function's type. - Function_type* type_; - // The enclosing function. This is NULL when there isn't one, which - // is the normal case. - Function* enclosing_; - // The result variables, if any. - Results* results_; - // If there is a closure, this is the list of variables which appear - // in the closure. This is created by the parser, and then resolved - // to a real type when we lower parse trees. - Closure_fields closure_fields_; - // The closure variable, passed as a parameter using the static - // chain parameter. Normally NULL. - Named_object* closure_var_; - // The outer block of statements in the function. - Block* block_; - // The source location of the start of the function. - Location location_; - // Labels defined or referenced in the function. - Labels labels_; - // The number of local types defined in this function. - unsigned int local_type_count_; - // The function decl. - tree fndecl_; - // The defer stack variable. A pointer to this variable is used to - // distinguish the defer stack for one function from another. This - // is NULL unless we actually need a defer stack. - Temporary_statement* defer_stack_; - // True if the result variables are named. - bool results_are_named_; - // True if this method should not be included in the type descriptor. - bool nointerface_; - // True if this function calls the predeclared recover function. - bool calls_recover_; - // True if this a thunk built for a function which calls recover. - bool is_recover_thunk_; - // True if this function already has a recover thunk. - bool has_recover_thunk_; - // True if this function should be put in a unique section. This is - // turned on for field tracking. - bool in_unique_section_ : 1; -}; - -// A snapshot of the current binding state. - -class Bindings_snapshot -{ - public: - Bindings_snapshot(const Block*, Location); - - // Report any errors appropriate for a goto from the current binding - // state of B to this one. - void - check_goto_from(const Block* b, Location); - - // Report any errors appropriate for a goto from this binding state - // to the current state of B. - void - check_goto_to(const Block* b); - - private: - bool - check_goto_block(Location, const Block*, const Block*, size_t*); - - void - check_goto_defs(Location, const Block*, size_t, size_t); - - // The current block. - const Block* block_; - // The number of names currently defined in each open block. - // Element 0 is this->block_, element 1 is - // this->block_->enclosing(), etc. - std::vector<size_t> counts_; - // The location where this snapshot was taken. - Location location_; -}; - -// A function declaration. - -class Function_declaration -{ - public: - Function_declaration(Function_type* fntype, Location location) - : fntype_(fntype), location_(location), asm_name_(), fndecl_(NULL) - { } - - Function_type* - type() const - { return this->fntype_; } - - Location - location() const - { return this->location_; } - - const std::string& - asm_name() const - { return this->asm_name_; } - - // Set the assembler name. - void - set_asm_name(const std::string& asm_name) - { this->asm_name_ = asm_name; } - - // Return a decl for the function given an identifier. - tree - get_or_make_decl(Gogo*, Named_object*, tree id); - - // Export a function declaration. - void - export_func(Export* exp, const std::string& name) const - { Function::export_func_with_type(exp, name, this->fntype_); } - - private: - // The type of the function. - Function_type* fntype_; - // The location of the declaration. - Location location_; - // The assembler name: this is the name to use in references to the - // function. This is normally empty. - std::string asm_name_; - // The function decl if needed. - tree fndecl_; -}; - -// A variable. - -class Variable -{ - public: - Variable(Type*, Expression*, bool is_global, bool is_parameter, - bool is_receiver, Location); - - // Get the type of the variable. - Type* - type(); - - Type* - type() const; - - // Return whether the type is defined yet. - bool - has_type() const; - - // Get the initial value. - Expression* - init() const - { return this->init_; } - - // Return whether there are any preinit statements. - bool - has_pre_init() const - { return this->preinit_ != NULL; } - - // Return the preinit statements if any. - Block* - preinit() const - { return this->preinit_; } - - // Return whether this is a global variable. - bool - is_global() const - { return this->is_global_; } - - // Return whether this is a function parameter. - bool - is_parameter() const - { return this->is_parameter_; } - - // Return whether this is the receiver parameter of a method. - bool - is_receiver() const - { return this->is_receiver_; } - - // Change this parameter to be a receiver. This is used when - // creating the thunks created for functions which call recover. - void - set_is_receiver() - { - go_assert(this->is_parameter_); - this->is_receiver_ = true; - } - - // Change this parameter to not be a receiver. This is used when - // creating the thunks created for functions which call recover. - void - set_is_not_receiver() - { - go_assert(this->is_parameter_); - this->is_receiver_ = false; - } - - // Return whether this is the varargs parameter of a function. - bool - is_varargs_parameter() const - { return this->is_varargs_parameter_; } - - // Whether this variable's address is taken. - bool - is_address_taken() const - { return this->is_address_taken_; } - - // Whether this variable should live in the heap. - bool - is_in_heap() const - { return this->is_address_taken_ && !this->is_global_; } - - // Note that something takes the address of this variable. - void - set_address_taken() - { this->is_address_taken_ = true; } - - // Return whether the address is taken but does not escape. - bool - is_non_escaping_address_taken() const - { return this->is_non_escaping_address_taken_; } - - // Note that something takes the address of this variable such that - // the address does not escape the function. - void - set_non_escaping_address_taken() - { this->is_non_escaping_address_taken_ = true; } - - // Get the source location of the variable's declaration. - Location - location() const - { return this->location_; } - - // Record that this is the varargs parameter of a function. - void - set_is_varargs_parameter() - { - go_assert(this->is_parameter_); - this->is_varargs_parameter_ = true; - } - - // Return whether the variable has been used. - bool - is_used() const - { return this->is_used_; } - - // Mark that the variable has been used. - void - set_is_used() - { this->is_used_ = true; } - - // Clear the initial value; used for error handling. - void - clear_init() - { this->init_ = NULL; } - - // Set the initial value; used for converting shortcuts. - void - set_init(Expression* init) - { this->init_ = init; } - - // Get the preinit block, a block of statements to be run before the - // initialization expression. - Block* - preinit_block(Gogo*); - - // Add a statement to be run before the initialization expression. - // This is only used for global variables. - void - add_preinit_statement(Gogo*, Statement*); - - // Lower the initialization expression after parsing is complete. - void - lower_init_expression(Gogo*, Named_object*, Statement_inserter*); - - // A special case: the init value is used only to determine the - // type. This is used if the variable is defined using := with the - // comma-ok form of a map index or a receive expression. The init - // value is actually the map index expression or receive expression. - // We use this because we may not know the right type at parse time. - void - set_type_from_init_tuple() - { this->type_from_init_tuple_ = true; } - - // Another special case: the init value is used only to determine - // the type. This is used if the variable is defined using := with - // a range clause. The init value is the range expression. The - // type of the variable is the index type of the range expression - // (i.e., the first value returned by a range). - void - set_type_from_range_index() - { this->type_from_range_index_ = true; } - - // Another special case: like set_type_from_range_index, but the - // type is the value type of the range expression (i.e., the second - // value returned by a range). - void - set_type_from_range_value() - { this->type_from_range_value_ = true; } - - // Another special case: the init value is used only to determine - // the type. This is used if the variable is defined using := with - // a case in a select statement. The init value is the channel. - // The type of the variable is the channel's element type. - void - set_type_from_chan_element() - { this->type_from_chan_element_ = true; } - - // After we lower the select statement, we once again set the type - // from the initialization expression. - void - clear_type_from_chan_element() - { - go_assert(this->type_from_chan_element_); - this->type_from_chan_element_ = false; - } - - // Note that this variable was created for a type switch clause. - void - set_is_type_switch_var() - { this->is_type_switch_var_ = true; } - - // Mark the variable as going into a unique section. - void - set_in_unique_section() - { - go_assert(this->is_global_); - this->in_unique_section_ = true; - } - - // Traverse the initializer expression. - int - traverse_expression(Traverse*, unsigned int traverse_mask); - - // Determine the type of the variable if necessary. - void - determine_type(); - - // Get the backend representation of the variable. - Bvariable* - get_backend_variable(Gogo*, Named_object*, const Package*, - const std::string&); - - // Get the initial value of the variable as a tree. This may only - // be called if has_pre_init() returns false. - tree - get_init_tree(Gogo*, Named_object* function); - - // Return a series of statements which sets the value of the - // variable in DECL. This should only be called is has_pre_init() - // returns true. DECL may be NULL for a sink variable. - tree - get_init_block(Gogo*, Named_object* function, tree decl); - - // Export the variable. - void - export_var(Export*, const std::string& name) const; - - // Import a variable. - static void - import_var(Import*, std::string* pname, Type** ptype); - - private: - // The type of a tuple. - Type* - type_from_tuple(Expression*, bool) const; - - // The type of a range. - Type* - type_from_range(Expression*, bool, bool) const; - - // The element type of a channel. - Type* - type_from_chan_element(Expression*, bool) const; - - // The variable's type. This may be NULL if the type is set from - // the expression. - Type* type_; - // The initial value. This may be NULL if the variable should be - // initialized to the default value for the type. - Expression* init_; - // Statements to run before the init statement. - Block* preinit_; - // Location of variable definition. - Location location_; - // Backend representation. - Bvariable* backend_; - // Whether this is a global variable. - bool is_global_ : 1; - // Whether this is a function parameter. - bool is_parameter_ : 1; - // Whether this is the receiver parameter of a method. - bool is_receiver_ : 1; - // Whether this is the varargs parameter of a function. - bool is_varargs_parameter_ : 1; - // Whether this variable is ever referenced. - bool is_used_ : 1; - // Whether something takes the address of this variable. For a - // local variable this implies that the variable has to be on the - // heap. - bool is_address_taken_ : 1; - // Whether something takes the address of this variable such that - // the address does not escape the function. - bool is_non_escaping_address_taken_ : 1; - // True if we have seen this variable in a traversal. - bool seen_ : 1; - // True if we have lowered the initialization expression. - bool init_is_lowered_ : 1; - // True if init is a tuple used to set the type. - bool type_from_init_tuple_ : 1; - // True if init is a range clause and the type is the index type. - bool type_from_range_index_ : 1; - // True if init is a range clause and the type is the value type. - bool type_from_range_value_ : 1; - // True if init is a channel and the type is the channel's element type. - bool type_from_chan_element_ : 1; - // True if this is a variable created for a type switch case. - bool is_type_switch_var_ : 1; - // True if we have determined types. - bool determined_type_ : 1; - // True if this variable should be put in a unique section. This is - // used for field tracking. - bool in_unique_section_ : 1; -}; - -// A variable which is really the name for a function return value, or -// part of one. - -class Result_variable -{ - public: - Result_variable(Type* type, Function* function, int index, - Location location) - : type_(type), function_(function), index_(index), location_(location), - backend_(NULL), is_address_taken_(false), - is_non_escaping_address_taken_(false) - { } - - // Get the type of the result variable. - Type* - type() const - { return this->type_; } - - // Get the function that this is associated with. - Function* - function() const - { return this->function_; } - - // Index in the list of function results. - int - index() const - { return this->index_; } - - // The location of the variable definition. - Location - location() const - { return this->location_; } - - // Whether this variable's address is taken. - bool - is_address_taken() const - { return this->is_address_taken_; } - - // Note that something takes the address of this variable. - void - set_address_taken() - { this->is_address_taken_ = true; } - - // Return whether the address is taken but does not escape. - bool - is_non_escaping_address_taken() const - { return this->is_non_escaping_address_taken_; } - - // Note that something takes the address of this variable such that - // the address does not escape the function. - void - set_non_escaping_address_taken() - { this->is_non_escaping_address_taken_ = true; } - - // Whether this variable should live in the heap. - bool - is_in_heap() const - { return this->is_address_taken_; } - - // Set the function. This is used when cloning functions which call - // recover. - void - set_function(Function* function) - { this->function_ = function; } - - // Get the backend representation of the variable. - Bvariable* - get_backend_variable(Gogo*, Named_object*, const std::string&); - - private: - // Type of result variable. - Type* type_; - // Function with which this is associated. - Function* function_; - // Index in list of results. - int index_; - // Where the result variable is defined. - Location location_; - // Backend representation. - Bvariable* backend_; - // Whether something takes the address of this variable. - bool is_address_taken_; - // Whether something takes the address of this variable such that - // the address does not escape the function. - bool is_non_escaping_address_taken_; -}; - -// The value we keep for a named constant. This lets us hold a type -// and an expression. - -class Named_constant -{ - public: - Named_constant(Type* type, Expression* expr, int iota_value, - Location location) - : type_(type), expr_(expr), iota_value_(iota_value), location_(location), - lowering_(false) - { } - - Type* - type() const - { return this->type_; } - - Expression* - expr() const - { return this->expr_; } - - int - iota_value() const - { return this->iota_value_; } - - Location - location() const - { return this->location_; } - - // Whether we are lowering. - bool - lowering() const - { return this->lowering_; } - - // Set that we are lowering. - void - set_lowering() - { this->lowering_ = true; } - - // We are no longer lowering. - void - clear_lowering() - { this->lowering_ = false; } - - // Traverse the expression. - int - traverse_expression(Traverse*); - - // Determine the type of the constant if necessary. - void - determine_type(); - - // Indicate that we found and reported an error for this constant. - void - set_error(); - - // Export the constant. - void - export_const(Export*, const std::string& name) const; - - // Import a constant. - static void - import_const(Import*, std::string*, Type**, Expression**); - - private: - // The type of the constant. - Type* type_; - // The expression for the constant. - Expression* expr_; - // If the predeclared constant iota is used in EXPR_, this is the - // value it will have. We do this because at parse time we don't - // know whether the name "iota" will refer to the predeclared - // constant or to something else. We put in the right value in when - // we lower. - int iota_value_; - // The location of the definition. - Location location_; - // Whether we are currently lowering this constant. - bool lowering_; -}; - -// A type declaration. - -class Type_declaration -{ - public: - Type_declaration(Location location) - : location_(location), in_function_(NULL), in_function_index_(0), - methods_(), issued_warning_(false) - { } - - // Return the location. - Location - location() const - { return this->location_; } - - // Return the function in which this type is declared. This will - // return NULL for a type declared in global scope. - Named_object* - in_function(unsigned int* pindex) - { - *pindex = this->in_function_index_; - return this->in_function_; - } - - // Set the function in which this type is declared. - void - set_in_function(Named_object* f, unsigned int index) - { - this->in_function_ = f; - this->in_function_index_ = index; - } - - // Add a method to this type. This is used when methods are defined - // before the type. - Named_object* - add_method(const std::string& name, Function* function); - - // Add a method declaration to this type. - Named_object* - add_method_declaration(const std::string& name, Package*, - Function_type* type, Location location); - - // Return whether any methods were defined. - bool - has_methods() const; - - // Return the methods. - const std::vector<Named_object*>* - methods() const - { return &this->methods_; } - - // Define methods when the real type is known. - void - define_methods(Named_type*); - - // This is called if we are trying to use this type. It returns - // true if we should issue a warning. - bool - using_type(); - - private: - // The location of the type declaration. - Location location_; - // If this type is declared in a function, a pointer back to the - // function in which it is defined. - Named_object* in_function_; - // The index of this type in IN_FUNCTION_. - unsigned int in_function_index_; - // Methods defined before the type is defined. - std::vector<Named_object*> methods_; - // True if we have issued a warning about a use of this type - // declaration when it is undefined. - bool issued_warning_; -}; - -// An unknown object. These are created by the parser for forward -// references to names which have not been seen before. In a correct -// program, these will always point to a real definition by the end of -// the parse. Because they point to another Named_object, these may -// only be referenced by Unknown_expression objects. - -class Unknown_name -{ - public: - Unknown_name(Location location) - : location_(location), real_named_object_(NULL) - { } - - // Return the location where this name was first seen. - Location - location() const - { return this->location_; } - - // Return the real named object that this points to, or NULL if it - // was never resolved. - Named_object* - real_named_object() const - { return this->real_named_object_; } - - // Set the real named object that this points to. - void - set_real_named_object(Named_object* no); - - private: - // The location where this name was first seen. - Location location_; - // The real named object when it is known. - Named_object* - real_named_object_; -}; - -// A named object named. This is the result of a declaration. We -// don't use a superclass because they all have to be handled -// differently. - -class Named_object -{ - public: - enum Classification - { - // An uninitialized Named_object. We should never see this. - NAMED_OBJECT_UNINITIALIZED, - // An erroneous name. This indicates a parse error, to avoid - // later errors about undefined references. - NAMED_OBJECT_ERRONEOUS, - // An unknown name. This is used for forward references. In a - // correct program, these will all be resolved by the end of the - // parse. - NAMED_OBJECT_UNKNOWN, - // A const. - NAMED_OBJECT_CONST, - // A type. - NAMED_OBJECT_TYPE, - // A forward type declaration. - NAMED_OBJECT_TYPE_DECLARATION, - // A var. - NAMED_OBJECT_VAR, - // A result variable in a function. - NAMED_OBJECT_RESULT_VAR, - // The blank identifier--the special variable named _. - NAMED_OBJECT_SINK, - // A func. - NAMED_OBJECT_FUNC, - // A forward func declaration. - NAMED_OBJECT_FUNC_DECLARATION, - // A package. - NAMED_OBJECT_PACKAGE - }; - - // Return the classification. - Classification - classification() const - { return this->classification_; } - - // Classifiers. - - bool - is_erroneous() const - { return this->classification_ == NAMED_OBJECT_ERRONEOUS; } - - bool - is_unknown() const - { return this->classification_ == NAMED_OBJECT_UNKNOWN; } - - bool - is_const() const - { return this->classification_ == NAMED_OBJECT_CONST; } - - bool - is_type() const - { return this->classification_ == NAMED_OBJECT_TYPE; } - - bool - is_type_declaration() const - { return this->classification_ == NAMED_OBJECT_TYPE_DECLARATION; } - - bool - is_variable() const - { return this->classification_ == NAMED_OBJECT_VAR; } - - bool - is_result_variable() const - { return this->classification_ == NAMED_OBJECT_RESULT_VAR; } - - bool - is_sink() const - { return this->classification_ == NAMED_OBJECT_SINK; } - - bool - is_function() const - { return this->classification_ == NAMED_OBJECT_FUNC; } - - bool - is_function_declaration() const - { return this->classification_ == NAMED_OBJECT_FUNC_DECLARATION; } - - bool - is_package() const - { return this->classification_ == NAMED_OBJECT_PACKAGE; } - - // Creators. - - static Named_object* - make_erroneous_name(const std::string& name) - { return new Named_object(name, NULL, NAMED_OBJECT_ERRONEOUS); } - - static Named_object* - make_unknown_name(const std::string& name, Location); - - static Named_object* - make_constant(const Typed_identifier&, const Package*, Expression*, - int iota_value); - - static Named_object* - make_type(const std::string&, const Package*, Type*, Location); - - static Named_object* - make_type_declaration(const std::string&, const Package*, Location); - - static Named_object* - make_variable(const std::string&, const Package*, Variable*); - - static Named_object* - make_result_variable(const std::string&, Result_variable*); - - static Named_object* - make_sink(); - - static Named_object* - make_function(const std::string&, const Package*, Function*); - - static Named_object* - make_function_declaration(const std::string&, const Package*, Function_type*, - Location); - - static Named_object* - make_package(const std::string& alias, Package* package); - - // Getters. - - Unknown_name* - unknown_value() - { - go_assert(this->classification_ == NAMED_OBJECT_UNKNOWN); - return this->u_.unknown_value; - } - - const Unknown_name* - unknown_value() const - { - go_assert(this->classification_ == NAMED_OBJECT_UNKNOWN); - return this->u_.unknown_value; - } - - Named_constant* - const_value() - { - go_assert(this->classification_ == NAMED_OBJECT_CONST); - return this->u_.const_value; - } - - const Named_constant* - const_value() const - { - go_assert(this->classification_ == NAMED_OBJECT_CONST); - return this->u_.const_value; - } - - Named_type* - type_value() - { - go_assert(this->classification_ == NAMED_OBJECT_TYPE); - return this->u_.type_value; - } - - const Named_type* - type_value() const - { - go_assert(this->classification_ == NAMED_OBJECT_TYPE); - return this->u_.type_value; - } - - Type_declaration* - type_declaration_value() - { - go_assert(this->classification_ == NAMED_OBJECT_TYPE_DECLARATION); - return this->u_.type_declaration; - } - - const Type_declaration* - type_declaration_value() const - { - go_assert(this->classification_ == NAMED_OBJECT_TYPE_DECLARATION); - return this->u_.type_declaration; - } - - Variable* - var_value() - { - go_assert(this->classification_ == NAMED_OBJECT_VAR); - return this->u_.var_value; - } - - const Variable* - var_value() const - { - go_assert(this->classification_ == NAMED_OBJECT_VAR); - return this->u_.var_value; - } - - Result_variable* - result_var_value() - { - go_assert(this->classification_ == NAMED_OBJECT_RESULT_VAR); - return this->u_.result_var_value; - } - - const Result_variable* - result_var_value() const - { - go_assert(this->classification_ == NAMED_OBJECT_RESULT_VAR); - return this->u_.result_var_value; - } - - Function* - func_value() - { - go_assert(this->classification_ == NAMED_OBJECT_FUNC); - return this->u_.func_value; - } - - const Function* - func_value() const - { - go_assert(this->classification_ == NAMED_OBJECT_FUNC); - return this->u_.func_value; - } - - Function_declaration* - func_declaration_value() - { - go_assert(this->classification_ == NAMED_OBJECT_FUNC_DECLARATION); - return this->u_.func_declaration_value; - } - - const Function_declaration* - func_declaration_value() const - { - go_assert(this->classification_ == NAMED_OBJECT_FUNC_DECLARATION); - return this->u_.func_declaration_value; - } - - Package* - package_value() - { - go_assert(this->classification_ == NAMED_OBJECT_PACKAGE); - return this->u_.package_value; - } - - const Package* - package_value() const - { - go_assert(this->classification_ == NAMED_OBJECT_PACKAGE); - return this->u_.package_value; - } - - const std::string& - name() const - { return this->name_; } - - // Return the name to use in an error message. The difference is - // that if this Named_object is defined in a different package, this - // will return PACKAGE.NAME. - std::string - message_name() const; - - const Package* - package() const - { return this->package_; } - - // Resolve an unknown value if possible. This returns the same - // Named_object or a new one. - Named_object* - resolve() - { - Named_object* ret = this; - if (this->is_unknown()) - { - Named_object* r = this->unknown_value()->real_named_object(); - if (r != NULL) - ret = r; - } - return ret; - } - - const Named_object* - resolve() const - { - const Named_object* ret = this; - if (this->is_unknown()) - { - const Named_object* r = this->unknown_value()->real_named_object(); - if (r != NULL) - ret = r; - } - return ret; - } - - // The location where this object was defined or referenced. - Location - location() const; - - // Convert a variable to the backend representation. - Bvariable* - get_backend_variable(Gogo*, Named_object* function); - - // Return a tree for the external identifier for this object. - tree - get_id(Gogo*); - - // Return a tree representing this object. - tree - get_tree(Gogo*, Named_object* function); - - // Define a type declaration. - void - set_type_value(Named_type*); - - // Define a function declaration. - void - set_function_value(Function*); - - // Declare an unknown name as a type declaration. - void - declare_as_type(); - - // Export this object. - void - export_named_object(Export*) const; - - private: - Named_object(const std::string&, const Package*, Classification); - - // The name of the object. - std::string name_; - // The package that this object is in. This is NULL if it is in the - // file we are compiling. - const Package* package_; - // The type of object this is. - Classification classification_; - // The real data. - union - { - Unknown_name* unknown_value; - Named_constant* const_value; - Named_type* type_value; - Type_declaration* type_declaration; - Variable* var_value; - Result_variable* result_var_value; - Function* func_value; - Function_declaration* func_declaration_value; - Package* package_value; - } u_; - // The DECL tree for this object if we have already converted it. - tree tree_; -}; - -// A binding contour. This binds names to objects. - -class Bindings -{ - public: - // Type for mapping from names to objects. - typedef Unordered_map(std::string, Named_object*) Contour; - - Bindings(Bindings* enclosing); - - // Add an erroneous name. - Named_object* - add_erroneous_name(const std::string& name) - { return this->add_named_object(Named_object::make_erroneous_name(name)); } - - // Add an unknown name. - Named_object* - add_unknown_name(const std::string& name, Location location) - { - return this->add_named_object(Named_object::make_unknown_name(name, - location)); - } - - // Add a constant. - Named_object* - add_constant(const Typed_identifier& tid, const Package* package, - Expression* expr, int iota_value) - { - return this->add_named_object(Named_object::make_constant(tid, package, - expr, - iota_value)); - } - - // Add a type. - Named_object* - add_type(const std::string& name, const Package* package, Type* type, - Location location) - { - return this->add_named_object(Named_object::make_type(name, package, type, - location)); - } - - // Add a named type. This is used for builtin types, and to add an - // imported type to the global scope. - Named_object* - add_named_type(Named_type* named_type); - - // Add a type declaration. - Named_object* - add_type_declaration(const std::string& name, const Package* package, - Location location) - { - Named_object* no = Named_object::make_type_declaration(name, package, - location); - return this->add_named_object(no); - } - - // Add a variable. - Named_object* - add_variable(const std::string& name, const Package* package, - Variable* variable) - { - return this->add_named_object(Named_object::make_variable(name, package, - variable)); - } - - // Add a result variable. - Named_object* - add_result_variable(const std::string& name, Result_variable* result) - { - return this->add_named_object(Named_object::make_result_variable(name, - result)); - } - - // Add a function. - Named_object* - add_function(const std::string& name, const Package*, Function* function); - - // Add a function declaration. - Named_object* - add_function_declaration(const std::string& name, const Package* package, - Function_type* type, Location location); - - // Add a package. The location is the location of the import - // statement. - Named_object* - add_package(const std::string& alias, Package* package) - { - Named_object* no = Named_object::make_package(alias, package); - return this->add_named_object(no); - } - - // Define a type which was already declared. - void - define_type(Named_object*, Named_type*); - - // Add a method to the list of objects. This is not added to the - // lookup table. - void - add_method(Named_object*); - - // Add a named object to this binding. - Named_object* - add_named_object(Named_object* no) - { return this->add_named_object_to_contour(&this->bindings_, no); } - - // Clear all names in file scope from the bindings. - void - clear_file_scope(Gogo*); - - // Look up a name in this binding contour and in any enclosing - // binding contours. This returns NULL if the name is not found. - Named_object* - lookup(const std::string&) const; - - // Look up a name in this binding contour without looking in any - // enclosing binding contours. Returns NULL if the name is not found. - Named_object* - lookup_local(const std::string&) const; - - // Remove a name. - void - remove_binding(Named_object*); - - // Mark all variables as used. This is used for some types of parse - // error. - void - mark_locals_used(); - - // Traverse the tree. See the Traverse class. - int - traverse(Traverse*, bool is_global); - - // Iterate over definitions. This does not include things which - // were only declared. - - typedef std::vector<Named_object*>::const_iterator - const_definitions_iterator; - - const_definitions_iterator - begin_definitions() const - { return this->named_objects_.begin(); } - - const_definitions_iterator - end_definitions() const - { return this->named_objects_.end(); } - - // Return the number of definitions. - size_t - size_definitions() const - { return this->named_objects_.size(); } - - // Return whether there are no definitions. - bool - empty_definitions() const - { return this->named_objects_.empty(); } - - // Iterate over declarations. This is everything that has been - // declared, which includes everything which has been defined. - - typedef Contour::const_iterator const_declarations_iterator; - - const_declarations_iterator - begin_declarations() const - { return this->bindings_.begin(); } - - const_declarations_iterator - end_declarations() const - { return this->bindings_.end(); } - - // Return the number of declarations. - size_t - size_declarations() const - { return this->bindings_.size(); } - - // Return whether there are no declarations. - bool - empty_declarations() const - { return this->bindings_.empty(); } - - // Return the first declaration. - Named_object* - first_declaration() - { return this->bindings_.empty() ? NULL : this->bindings_.begin()->second; } - - private: - Named_object* - add_named_object_to_contour(Contour*, Named_object*); - - Named_object* - new_definition(Named_object*, Named_object*); - - // Enclosing bindings. - Bindings* enclosing_; - // The list of objects. - std::vector<Named_object*> named_objects_; - // The mapping from names to objects. - Contour bindings_; -}; - -// A label. - -class Label -{ - public: - Label(const std::string& name) - : name_(name), location_(Linemap::unknown_location()), snapshot_(NULL), - refs_(), is_used_(false), blabel_(NULL) - { } - - // Return the label's name. - const std::string& - name() const - { return this->name_; } - - // Return whether the label has been defined. - bool - is_defined() const - { return !Linemap::is_unknown_location(this->location_); } - - // Return whether the label has been used. - bool - is_used() const - { return this->is_used_; } - - // Record that the label is used. - void - set_is_used() - { this->is_used_ = true; } - - // Return the location of the definition. - Location - location() const - { return this->location_; } - - // Return the bindings snapshot. - Bindings_snapshot* - snapshot() const - { return this->snapshot_; } - - // Add a snapshot of a goto which refers to this label. - void - add_snapshot_ref(Bindings_snapshot* snapshot) - { - go_assert(Linemap::is_unknown_location(this->location_)); - this->refs_.push_back(snapshot); - } - - // Return the list of snapshots of goto statements which refer to - // this label. - const std::vector<Bindings_snapshot*>& - refs() const - { return this->refs_; } - - // Clear the references. - void - clear_refs(); - - // Define the label at LOCATION with the given bindings snapshot. - void - define(Location location, Bindings_snapshot* snapshot) - { - go_assert(Linemap::is_unknown_location(this->location_) - && this->snapshot_ == NULL); - this->location_ = location; - this->snapshot_ = snapshot; - } - - // Return the backend representation for this label. - Blabel* - get_backend_label(Translate_context*); - - // Return an expression for the address of this label. This is used - // to get the return address of a deferred function to see whether - // the function may call recover. - Bexpression* - get_addr(Translate_context*, Location location); - - private: - // The name of the label. - std::string name_; - // The location of the definition. This is 0 if the label has not - // yet been defined. - Location location_; - // A snapshot of the set of bindings defined at this label, used to - // issue errors about invalid goto statements. - Bindings_snapshot* snapshot_; - // A list of snapshots of goto statements which refer to this label. - std::vector<Bindings_snapshot*> refs_; - // Whether the label has been used. - bool is_used_; - // The backend representation. - Blabel* blabel_; -}; - -// An unnamed label. These are used when lowering loops. - -class Unnamed_label -{ - public: - Unnamed_label(Location location) - : location_(location), blabel_(NULL) - { } - - // Get the location where the label is defined. - Location - location() const - { return this->location_; } - - // Set the location where the label is defined. - void - set_location(Location location) - { this->location_ = location; } - - // Return a statement which defines this label. - Bstatement* - get_definition(Translate_context*); - - // Return a goto to this label from LOCATION. - Bstatement* - get_goto(Translate_context*, Location location); - - private: - // Return the backend representation. - Blabel* - get_blabel(Translate_context*); - - // The location where the label is defined. - Location location_; - // The backend representation of this label. - Blabel* blabel_; -}; - -// An imported package. - -class Package -{ - public: - Package(const std::string& pkgpath, Location location); - - // Get the package path used for all symbols exported from this - // package. - const std::string& - pkgpath() const - { return this->pkgpath_; } - - // Return the package path to use for a symbol name. - const std::string& - pkgpath_symbol() const - { return this->pkgpath_symbol_; } - - // Return the location of the import statement. - Location - location() const - { return this->location_; } - - // Return whether we know the name of this package yet. - bool - has_package_name() const - { return !this->package_name_.empty(); } - - // The name that this package uses in its package clause. This may - // be different from the name in the associated Named_object if the - // import statement used an alias. - const std::string& - package_name() const - { - go_assert(!this->package_name_.empty()); - return this->package_name_; - } - - // The priority of this package. The init function of packages with - // lower priority must be run before the init function of packages - // with higher priority. - int - priority() const - { return this->priority_; } - - // Set the priority. - void - set_priority(int priority); - - // Return the bindings. - Bindings* - bindings() - { return this->bindings_; } - - // Whether some symbol from the package was used. - bool - used() const - { return this->used_; } - - // Note that some symbol from this package was used. - void - set_used() const - { this->used_ = true; } - - // Clear the used field for the next file. - void - clear_used() - { this->used_ = false; } - - // Whether this package was imported in the current file. - bool - is_imported() const - { return this->is_imported_; } - - // Note that this package was imported in the current file. - void - set_is_imported() - { this->is_imported_ = true; } - - // Clear the imported field for the next file. - void - clear_is_imported() - { this->is_imported_ = false; } - - // Whether this package was imported with a name of "_". - bool - uses_sink_alias() const - { return this->uses_sink_alias_; } - - // Note that this package was imported with a name of "_". - void - set_uses_sink_alias() - { this->uses_sink_alias_ = true; } - - // Clear the sink alias field for the next file. - void - clear_uses_sink_alias() - { this->uses_sink_alias_ = false; } - - // Look up a name in the package. Returns NULL if the name is not - // found. - Named_object* - lookup(const std::string& name) const - { return this->bindings_->lookup(name); } - - // Set the name of the package. - void - set_package_name(const std::string& name, Location); - - // Set the location of the package. This is used to record the most - // recent import location. - void - set_location(Location location) - { this->location_ = location; } - - // Add a constant to the package. - Named_object* - add_constant(const Typed_identifier& tid, Expression* expr) - { return this->bindings_->add_constant(tid, this, expr, 0); } - - // Add a type to the package. - Named_object* - add_type(const std::string& name, Type* type, Location location) - { return this->bindings_->add_type(name, this, type, location); } - - // Add a type declaration to the package. - Named_object* - add_type_declaration(const std::string& name, Location location) - { return this->bindings_->add_type_declaration(name, this, location); } - - // Add a variable to the package. - Named_object* - add_variable(const std::string& name, Variable* variable) - { return this->bindings_->add_variable(name, this, variable); } - - // Add a function declaration to the package. - Named_object* - add_function_declaration(const std::string& name, Function_type* type, - Location loc) - { return this->bindings_->add_function_declaration(name, this, type, loc); } - - // Determine types of constants. - void - determine_types(); - - private: - // The package path for type reflection data. - std::string pkgpath_; - // The package path for symbol names. - std::string pkgpath_symbol_; - // The name that this package uses in the package clause. This may - // be the empty string if it is not yet known. - std::string package_name_; - // The names in this package. - Bindings* bindings_; - // The priority of this package. A package has a priority higher - // than the priority of all of the packages that it imports. This - // is used to run init functions in the right order. - int priority_; - // The location of the import statement. - Location location_; - // True if some name from this package was used. This is mutable - // because we can use a package even if we have a const pointer to - // it. - mutable bool used_; - // True if this package was imported in the current file. - bool is_imported_; - // True if this package was imported with a name of "_". - bool uses_sink_alias_; -}; - -// Return codes for the traversal functions. This is not an enum -// because we want to be able to declare traversal functions in other -// header files without including this one. - -// Continue traversal as usual. -const int TRAVERSE_CONTINUE = -1; - -// Exit traversal. -const int TRAVERSE_EXIT = 0; - -// Continue traversal, but skip components of the current object. -// E.g., if this is returned by Traverse::statement, we do not -// traverse the expressions in the statement even if -// traverse_expressions is set in the traverse_mask. -const int TRAVERSE_SKIP_COMPONENTS = 1; - -// This class is used when traversing the parse tree. The caller uses -// a subclass which overrides functions as desired. - -class Traverse -{ - public: - // These bitmasks say what to traverse. - static const unsigned int traverse_variables = 0x1; - static const unsigned int traverse_constants = 0x2; - static const unsigned int traverse_functions = 0x4; - static const unsigned int traverse_blocks = 0x8; - static const unsigned int traverse_statements = 0x10; - static const unsigned int traverse_expressions = 0x20; - static const unsigned int traverse_types = 0x40; - - Traverse(unsigned int traverse_mask) - : traverse_mask_(traverse_mask), types_seen_(NULL), expressions_seen_(NULL) - { } - - virtual ~Traverse(); - - // The bitmask of what to traverse. - unsigned int - traverse_mask() const - { return this->traverse_mask_; } - - // Record that we are going to traverse a type. This returns true - // if the type has already been seen in this traversal. This is - // required because types, unlike expressions, can form a circular - // graph. - bool - remember_type(const Type*); - - // Record that we are going to see an expression. This returns true - // if the expression has already been seen in this traversal. This - // is only needed for cases where multiple expressions can point to - // a single one. - bool - remember_expression(const Expression*); - - // These functions return one of the TRAVERSE codes defined above. - - // If traverse_variables is set in the mask, this is called for - // every variable in the tree. - virtual int - variable(Named_object*); - - // If traverse_constants is set in the mask, this is called for - // every named constant in the tree. The bool parameter is true for - // a global constant. - virtual int - constant(Named_object*, bool); - - // If traverse_functions is set in the mask, this is called for - // every function in the tree. - virtual int - function(Named_object*); - - // If traverse_blocks is set in the mask, this is called for every - // block in the tree. - virtual int - block(Block*); - - // If traverse_statements is set in the mask, this is called for - // every statement in the tree. - virtual int - statement(Block*, size_t* index, Statement*); - - // If traverse_expressions is set in the mask, this is called for - // every expression in the tree. - virtual int - expression(Expression**); - - // If traverse_types is set in the mask, this is called for every - // type in the tree. - virtual int - type(Type*); - - private: - // A hash table for types we have seen during this traversal. Note - // that this uses the default hash functions for pointers rather - // than Type_hash_identical and Type_identical. This is because for - // traversal we care about seeing a specific type structure. If - // there are two separate instances of identical types, we want to - // traverse both. - typedef Unordered_set(const Type*) Types_seen; - - typedef Unordered_set(const Expression*) Expressions_seen; - - // Bitmask of what sort of objects to traverse. - unsigned int traverse_mask_; - // Types which have been seen in this traversal. - Types_seen* types_seen_; - // Expressions which have been seen in this traversal. - Expressions_seen* expressions_seen_; -}; - -// A class which makes it easier to insert new statements before the -// current statement during a traversal. - -class Statement_inserter -{ - public: - // Empty constructor. - Statement_inserter() - : block_(NULL), pindex_(NULL), gogo_(NULL), var_(NULL) - { } - - // Constructor for a statement in a block. - Statement_inserter(Block* block, size_t *pindex) - : block_(block), pindex_(pindex), gogo_(NULL), var_(NULL) - { } - - // Constructor for a global variable. - Statement_inserter(Gogo* gogo, Variable* var) - : block_(NULL), pindex_(NULL), gogo_(gogo), var_(var) - { go_assert(var->is_global()); } - - // We use the default copy constructor and assignment operator. - - // Insert S before the statement we are traversing, or before the - // initialization expression of a global variable. - void - insert(Statement* s); - - private: - // The block that the statement is in. - Block* block_; - // The index of the statement that we are traversing. - size_t* pindex_; - // The IR, needed when looking at an initializer expression for a - // global variable. - Gogo* gogo_; - // The global variable, when looking at an initializer expression. - Variable* var_; -}; - -// When translating the gogo IR into the backend data structure, this -// is the context we pass down the blocks and statements. - -class Translate_context -{ - public: - Translate_context(Gogo* gogo, Named_object* function, Block* block, - Bblock* bblock) - : gogo_(gogo), backend_(gogo->backend()), function_(function), - block_(block), bblock_(bblock), is_const_(false) - { } - - // Accessors. - - Gogo* - gogo() - { return this->gogo_; } - - Backend* - backend() - { return this->backend_; } - - Named_object* - function() - { return this->function_; } - - Block* - block() - { return this->block_; } - - Bblock* - bblock() - { return this->bblock_; } - - bool - is_const() - { return this->is_const_; } - - // Make a constant context. - void - set_is_const() - { this->is_const_ = true; } - - private: - // The IR for the entire compilation unit. - Gogo* gogo_; - // The generator for the backend data structures. - Backend* backend_; - // The function we are currently translating. NULL if not in a - // function, e.g., the initializer of a global variable. - Named_object* function_; - // The block we are currently translating. NULL if not in a - // function. - Block *block_; - // The backend representation of the current block. NULL if block_ - // is NULL. - Bblock* bblock_; - // Whether this is being evaluated in a constant context. This is - // used for type descriptor initializers. - bool is_const_; -}; - -// Runtime error codes. These must match the values in -// libgo/runtime/go-runtime-error.c. - -// Slice index out of bounds: negative or larger than the length of -// the slice. -static const int RUNTIME_ERROR_SLICE_INDEX_OUT_OF_BOUNDS = 0; - -// Array index out of bounds. -static const int RUNTIME_ERROR_ARRAY_INDEX_OUT_OF_BOUNDS = 1; - -// String index out of bounds. -static const int RUNTIME_ERROR_STRING_INDEX_OUT_OF_BOUNDS = 2; - -// Slice slice out of bounds: negative or larger than the length of -// the slice or high bound less than low bound. -static const int RUNTIME_ERROR_SLICE_SLICE_OUT_OF_BOUNDS = 3; - -// Array slice out of bounds. -static const int RUNTIME_ERROR_ARRAY_SLICE_OUT_OF_BOUNDS = 4; - -// String slice out of bounds. -static const int RUNTIME_ERROR_STRING_SLICE_OUT_OF_BOUNDS = 5; - -// Dereference of nil pointer. This is used when there is a -// dereference of a pointer to a very large struct or array, to ensure -// that a gigantic array is not used a proxy to access random memory -// locations. -static const int RUNTIME_ERROR_NIL_DEREFERENCE = 6; - -// Slice length or capacity out of bounds in make: negative or -// overflow or length greater than capacity. -static const int RUNTIME_ERROR_MAKE_SLICE_OUT_OF_BOUNDS = 7; - -// Map capacity out of bounds in make: negative or overflow. -static const int RUNTIME_ERROR_MAKE_MAP_OUT_OF_BOUNDS = 8; - -// Channel capacity out of bounds in make: negative or overflow. -static const int RUNTIME_ERROR_MAKE_CHAN_OUT_OF_BOUNDS = 9; - -// Division by zero. -static const int RUNTIME_ERROR_DIVISION_BY_ZERO = 10; - -// This is used by some of the langhooks. -extern Gogo* go_get_gogo(); - -// Whether we have seen any errors. FIXME: Replace with a backend -// interface. -extern bool saw_errors(); - -#endif // !defined(GO_GOGO_H) diff --git a/gcc-4.8.1/gcc/go/gofrontend/import-archive.cc b/gcc-4.8.1/gcc/go/gofrontend/import-archive.cc deleted file mode 100644 index 9a1d5b3d7..000000000 --- a/gcc-4.8.1/gcc/go/gofrontend/import-archive.cc +++ /dev/null @@ -1,660 +0,0 @@ -// import-archive.cc -- Go frontend read import data from an archive file. - -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "go-system.h" - -#include "import.h" - -#ifndef O_BINARY -#define O_BINARY 0 -#endif - -// Archive magic numbers. - -static const char armag[] = -{ - '!', '<', 'a', 'r', 'c', 'h', '>', '\n' -}; - -static const char armagt[] = -{ - '!', '<', 't', 'h', 'i', 'n', '>', '\n' -}; - -static const char arfmag[2] = { '`', '\n' }; - -// The header of an entry in an archive. This is all readable text, -// padded with spaces where necesary. - -struct Archive_header -{ - // The entry name. - char ar_name[16]; - // The file modification time. - char ar_date[12]; - // The user's UID in decimal. - char ar_uid[6]; - // The user's GID in decimal. - char ar_gid[6]; - // The file mode in octal. - char ar_mode[8]; - // The file size in decimal. - char ar_size[10]; - // The final magic code. - char ar_fmag[2]; -}; - -// The functions in this file extract Go export data from an archive. - -const int Import::archive_magic_len; - -// Return true if BYTES, which are from the start of the file, are an -// archive magic number. - -bool -Import::is_archive_magic(const char* bytes) -{ - return (memcmp(bytes, armag, Import::archive_magic_len) == 0 - || memcmp(bytes, armagt, Import::archive_magic_len) == 0); -} - -// An object used to read an archive file. - -class Archive_file -{ - public: - Archive_file(const std::string& filename, int fd, Location location) - : filename_(filename), fd_(fd), filesize_(-1), extended_names_(), - is_thin_archive_(false), location_(location), nested_archives_() - { } - - // Initialize. - bool - initialize(); - - // Return the file name. - const std::string& - filename() const - { return this->filename_; } - - // Get the file size. - off_t - filesize() const - { return this->filesize_; } - - // Return whether this is a thin archive. - bool - is_thin_archive() const - { return this->is_thin_archive_; } - - // Return the location of the import statement. - Location - location() const - { return this->location_; } - - // Read bytes. - bool - read(off_t offset, off_t size, char*); - - // Read the archive header at OFF, setting *PNAME, *SIZE, and - // *NESTED_OFF. - bool - read_header(off_t off, std::string* pname, off_t* size, off_t* nested_off); - - // Interpret the header of HDR, the header of the archive member at - // file offset OFF. Return whether it succeeded. Set *SIZE to the - // size of the member. Set *PNAME to the name of the member. Set - // *NESTED_OFF to the offset in a nested archive. - bool - interpret_header(const Archive_header* hdr, off_t off, - std::string* pname, off_t* size, off_t* nested_off) const; - - // Get the file and offset for an archive member. - bool - get_file_and_offset(off_t off, const std::string& hdrname, - off_t nested_off, int* memfd, off_t* memoff, - std::string* memname); - - private: - // For keeping track of open nested archives in a thin archive file. - typedef std::map<std::string, Archive_file*> Nested_archive_table; - - // The name of the file. - std::string filename_; - // The file descriptor. - int fd_; - // The file size; - off_t filesize_; - // The extended name table. - std::string extended_names_; - // Whether this is a thin archive. - bool is_thin_archive_; - // The location of the import statements. - Location location_; - // Table of nested archives. - Nested_archive_table nested_archives_; -}; - -bool -Archive_file::initialize() -{ - struct stat st; - if (fstat(this->fd_, &st) < 0) - { - error_at(this->location_, "%s: %m", this->filename_.c_str()); - return false; - } - this->filesize_ = st.st_size; - - char buf[sizeof(armagt)]; - if (::lseek(this->fd_, 0, SEEK_SET) < 0 - || ::read(this->fd_, buf, sizeof(armagt)) != sizeof(armagt)) - { - error_at(this->location_, "%s: %m", this->filename_.c_str()); - return false; - } - this->is_thin_archive_ = memcmp(buf, armagt, sizeof(armagt)) == 0; - - if (this->filesize_ == sizeof(armag)) - { - // Empty archive. - return true; - } - - // Look for the extended name table. - std::string filename; - off_t size; - if (!this->read_header(sizeof(armagt), &filename, &size, NULL)) - return false; - if (filename.empty()) - { - // We found the symbol table. - off_t off = sizeof(armagt) + sizeof(Archive_header) + size; - if ((off & 1) != 0) - ++off; - if (!this->read_header(off, &filename, &size, NULL)) - filename.clear(); - } - if (filename == "/") - { - char* rdbuf = new char[size]; - if (::read(this->fd_, rdbuf, size) != size) - { - error_at(this->location_, "%s: could not read extended names", - filename.c_str()); - delete[] rdbuf; - return false; - } - this->extended_names_.assign(rdbuf, size); - delete[] rdbuf; - } - - return true; -} - -// Read bytes from the file. - -bool -Archive_file::read(off_t offset, off_t size, char* buf) -{ - if (::lseek(this->fd_, offset, SEEK_SET) < 0 - || ::read(this->fd_, buf, size) != size) - { - error_at(this->location_, "%s: %m", this->filename_.c_str()); - return false; - } - return true; -} - -// Read the header at OFF. Set *PNAME to the name, *SIZE to the size, -// and *NESTED_OFF to the nested offset. - -bool -Archive_file::read_header(off_t off, std::string* pname, off_t* size, - off_t* nested_off) -{ - Archive_header hdr; - if (::lseek(this->fd_, off, SEEK_SET) < 0) - { - error_at(this->location_, "%s: %m", this->filename_.c_str()); - return false; - } - ssize_t got = ::read(this->fd_, &hdr, sizeof hdr); - if (got != sizeof hdr) - { - if (got < 0) - error_at(this->location_, "%s: %m", this->filename_.c_str()); - else if (got > 0) - error_at(this->location_, "%s: short archive header at %ld", - this->filename_.c_str(), static_cast<long>(off)); - else - error_at(this->location_, "%s: unexpected EOF at %ld", - this->filename_.c_str(), static_cast<long>(off)); - } - off_t local_nested_off; - if (!this->interpret_header(&hdr, off, pname, size, &local_nested_off)) - return false; - if (nested_off != NULL) - *nested_off = local_nested_off; - return true; -} - -// Interpret the header of HDR, the header of the archive member at -// file offset OFF. - -bool -Archive_file::interpret_header(const Archive_header* hdr, off_t off, - std::string* pname, off_t* size, - off_t* nested_off) const -{ - if (memcmp(hdr->ar_fmag, arfmag, sizeof arfmag) != 0) - { - error_at(this->location_, "%s: malformed archive header at %lu", - this->filename_.c_str(), static_cast<unsigned long>(off)); - return false; - } - - const int size_string_size = sizeof hdr->ar_size; - char size_string[size_string_size + 1]; - memcpy(size_string, hdr->ar_size, size_string_size); - char* ps = size_string + size_string_size; - while (ps[-1] == ' ') - --ps; - *ps = '\0'; - - errno = 0; - char* end; - *size = strtol(size_string, &end, 10); - if (*end != '\0' - || *size < 0 - || (*size == LONG_MAX && errno == ERANGE)) - { - error_at(this->location_, "%s: malformed archive header size at %lu", - this->filename_.c_str(), static_cast<unsigned long>(off)); - return false; - } - - *nested_off = 0; - if (hdr->ar_name[0] != '/') - { - const char* name_end = strchr(hdr->ar_name, '/'); - if (name_end == NULL - || name_end - hdr->ar_name >= static_cast<int>(sizeof hdr->ar_name)) - { - error_at(this->location_, "%s: malformed archive header name at %lu", - this->filename_.c_str(), static_cast<unsigned long>(off)); - return false; - } - pname->assign(hdr->ar_name, name_end - hdr->ar_name); - } - else if (hdr->ar_name[1] == ' ') - { - // This is the symbol table. - pname->clear(); - } - else if (hdr->ar_name[1] == '/') - { - // This is the extended name table. - pname->assign(1, '/'); - } - else - { - errno = 0; - long x = strtol(hdr->ar_name + 1, &end, 10); - long y = 0; - if (*end == ':') - y = strtol(end + 1, &end, 10); - if (*end != ' ' - || x < 0 - || (x == LONG_MAX && errno == ERANGE) - || static_cast<size_t>(x) >= this->extended_names_.size()) - { - error_at(this->location_, "%s: bad extended name index at %lu", - this->filename_.c_str(), static_cast<unsigned long>(off)); - return false; - } - - const char* name = this->extended_names_.data() + x; - const char* name_end = strchr(name, '\n'); - if (static_cast<size_t>(name_end - name) > this->extended_names_.size() - || name_end[-1] != '/') - { - error_at(this->location_, "%s: bad extended name entry at header %lu", - this->filename_.c_str(), static_cast<unsigned long>(off)); - return false; - } - pname->assign(name, name_end - 1 - name); - *nested_off = y; - } - - return true; -} - -// Get the file and offset for an archive member. - -bool -Archive_file::get_file_and_offset(off_t off, const std::string& hdrname, - off_t nested_off, int* memfd, off_t* memoff, - std::string* memname) -{ - if (!this->is_thin_archive_) - { - *memfd = this->fd_; - *memoff = off + sizeof(Archive_header); - *memname = this->filename_ + '(' + hdrname + ')'; - return true; - } - - std::string filename = hdrname; - if (!IS_ABSOLUTE_PATH(filename.c_str())) - { - const char* archive_path = this->filename_.c_str(); - const char* basename = lbasename(archive_path); - if (basename > archive_path) - filename.replace(0, 0, - this->filename_.substr(0, basename - archive_path)); - } - - if (nested_off > 0) - { - // This is a member of a nested archive. - Archive_file* nfile; - Nested_archive_table::const_iterator p = - this->nested_archives_.find(filename); - if (p != this->nested_archives_.end()) - nfile = p->second; - else - { - int nfd = open(filename.c_str(), O_RDONLY | O_BINARY); - if (nfd < 0) - { - error_at(this->location_, "%s: can't open nested archive %s", - this->filename_.c_str(), filename.c_str()); - return false; - } - nfile = new Archive_file(filename, nfd, this->location_); - if (!nfile->initialize()) - { - delete nfile; - return false; - } - this->nested_archives_[filename] = nfile; - } - - std::string nname; - off_t nsize; - off_t nnested_off; - if (!nfile->read_header(nested_off, &nname, &nsize, &nnested_off)) - return false; - return nfile->get_file_and_offset(nested_off, nname, nnested_off, - memfd, memoff, memname); - } - - // An external member of a thin archive. - *memfd = open(filename.c_str(), O_RDONLY | O_BINARY); - if (*memfd < 0) - { - error_at(this->location_, "%s: %m", filename.c_str()); - return false; - } - *memoff = 0; - *memname = filename; - return true; -} - -// An archive member iterator. This is more-or-less copied from gold. - -class Archive_iterator -{ - public: - // The header of an archive member. This is what this iterator - // points to. - struct Header - { - // The name of the member. - std::string name; - // The file offset of the member. - off_t off; - // The file offset of a nested archive member. - off_t nested_off; - // The size of the member. - off_t size; - }; - - Archive_iterator(Archive_file* afile, off_t off) - : afile_(afile), off_(off) - { this->read_next_header(); } - - const Header& - operator*() const - { return this->header_; } - - const Header* - operator->() const - { return &this->header_; } - - Archive_iterator& - operator++() - { - if (this->off_ == this->afile_->filesize()) - return *this; - this->off_ += sizeof(Archive_header); - if (!this->afile_->is_thin_archive()) - this->off_ += this->header_.size; - if ((this->off_ & 1) != 0) - ++this->off_; - this->read_next_header(); - return *this; - } - - Archive_iterator - operator++(int) - { - Archive_iterator ret = *this; - ++*this; - return ret; - } - - bool - operator==(const Archive_iterator p) const - { return this->off_ == p->off; } - - bool - operator!=(const Archive_iterator p) const - { return this->off_ != p->off; } - - private: - void - read_next_header(); - - // The underlying archive file. - Archive_file* afile_; - // The current offset in the file. - off_t off_; - // The current archive header. - Header header_; -}; - -// Read the next archive header. - -void -Archive_iterator::read_next_header() -{ - off_t filesize = this->afile_->filesize(); - while (true) - { - if (filesize - this->off_ < static_cast<off_t>(sizeof(Archive_header))) - { - if (filesize != this->off_) - { - error_at(this->afile_->location(), - "%s: short archive header at %lu", - this->afile_->filename().c_str(), - static_cast<unsigned long>(this->off_)); - this->off_ = filesize; - } - this->header_.off = filesize; - return; - } - - char buf[sizeof(Archive_header)]; - if (!this->afile_->read(this->off_, sizeof(Archive_header), buf)) - { - this->header_.off = filesize; - return; - } - - const Archive_header* hdr = reinterpret_cast<const Archive_header*>(buf); - if (!this->afile_->interpret_header(hdr, this->off_, &this->header_.name, - &this->header_.size, - &this->header_.nested_off)) - { - this->header_.off = filesize; - return; - } - this->header_.off = this->off_; - - // Skip special members. - if (!this->header_.name.empty() && this->header_.name != "/") - return; - - this->off_ += sizeof(Archive_header) + this->header_.size; - if ((this->off_ & 1) != 0) - ++this->off_; - } -} - -// Initial iterator. - -Archive_iterator -archive_begin(Archive_file* afile) -{ - return Archive_iterator(afile, sizeof(armag)); -} - -// Final iterator. - -Archive_iterator -archive_end(Archive_file* afile) -{ - return Archive_iterator(afile, afile->filesize()); -} - -// A type of Import_stream which concatenates other Import_streams -// together. - -class Stream_concatenate : public Import::Stream -{ - public: - Stream_concatenate() - : inputs_() - { } - - // Add a new stream. - void - add(Import::Stream* is) - { this->inputs_.push_back(is); } - - protected: - bool - do_peek(size_t, const char**); - - void - do_advance(size_t); - - private: - std::list<Import::Stream*> inputs_; -}; - -// Peek ahead. - -bool -Stream_concatenate::do_peek(size_t length, const char** bytes) -{ - while (true) - { - if (this->inputs_.empty()) - return false; - if (this->inputs_.front()->peek(length, bytes)) - return true; - delete this->inputs_.front(); - this->inputs_.pop_front(); - } -} - -// Advance. - -void -Stream_concatenate::do_advance(size_t skip) -{ - while (true) - { - if (this->inputs_.empty()) - return; - if (!this->inputs_.front()->at_eof()) - { - // We just assume that this will do the right thing. It - // should be OK since we should never want to skip past - // multiple streams. - this->inputs_.front()->advance(skip); - return; - } - delete this->inputs_.front(); - this->inputs_.pop_front(); - } -} - -// Import data from an archive. We walk through the archive and -// import data from each member. - -Import::Stream* -Import::find_archive_export_data(const std::string& filename, int fd, - Location location) -{ - Archive_file afile(filename, fd, location); - if (!afile.initialize()) - return NULL; - - Stream_concatenate* ret = new Stream_concatenate; - - bool any_data = false; - bool any_members = false; - Archive_iterator pend = archive_end(&afile); - for (Archive_iterator p = archive_begin(&afile); p != pend; p++) - { - any_members = true; - int member_fd; - off_t member_off; - std::string member_name; - if (!afile.get_file_and_offset(p->off, p->name, p->nested_off, - &member_fd, &member_off, &member_name)) - return NULL; - - Import::Stream* is = Import::find_object_export_data(member_name, - member_fd, - member_off, - location); - if (is != NULL) - { - ret->add(is); - any_data = true; - } - } - - if (!any_members) - { - // It's normal to have an empty archive file when using gobuild. - return new Stream_from_string(""); - } - - if (!any_data) - { - delete ret; - return NULL; - } - - return ret; -} diff --git a/gcc-4.8.1/gcc/go/gofrontend/import.cc b/gcc-4.8.1/gcc/go/gofrontend/import.cc deleted file mode 100644 index 4913100b5..000000000 --- a/gcc-4.8.1/gcc/go/gofrontend/import.cc +++ /dev/null @@ -1,960 +0,0 @@ -// import.cc -- Go frontend import declarations. - -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "go-system.h" - -#include "filenames.h" -#include "simple-object.h" - -#include "go-c.h" -#include "gogo.h" -#include "lex.h" -#include "types.h" -#include "export.h" -#include "import.h" - -#ifndef O_BINARY -#define O_BINARY 0 -#endif - -// The list of paths we search for import files. - -static std::vector<std::string> search_path; - -// Add a directory to the search path. This is called from the option -// handling language hook. - -GO_EXTERN_C -void -go_add_search_path(const char* path) -{ - search_path.push_back(std::string(path)); -} - -// Find import data. This searches the file system for FILENAME and -// returns a pointer to a Stream object to read the data that it -// exports. If the file is not found, it returns NULL. - -// When FILENAME is not an absolute path and does not start with ./ or -// ../, we use the search path provided by -I and -L options. - -// When FILENAME does start with ./ or ../, we use -// RELATIVE_IMPORT_PATH as a prefix. - -// When FILENAME does not exist, we try modifying FILENAME to find the -// file. We use the first of these which exists: -// * We append ".gox". -// * We turn the base of FILENAME into libFILENAME.so. -// * We turn the base of FILENAME into libFILENAME.a. -// * We append ".o". - -// When using a search path, we apply each of these transformations at -// each entry on the search path before moving on to the next entry. -// If the file exists, but does not contain any Go export data, we -// stop; we do not keep looking for another file with the same name -// later in the search path. - -Import::Stream* -Import::open_package(const std::string& filename, Location location, - const std::string& relative_import_path) -{ - bool is_local; - if (IS_ABSOLUTE_PATH(filename)) - is_local = true; - else if (filename[0] == '.' - && (filename[1] == '\0' || IS_DIR_SEPARATOR(filename[1]))) - is_local = true; - else if (filename[0] == '.' - && filename[1] == '.' - && (filename[2] == '\0' || IS_DIR_SEPARATOR(filename[2]))) - is_local = true; - else - is_local = false; - - std::string fn = filename; - if (is_local && !IS_ABSOLUTE_PATH(filename) && !relative_import_path.empty()) - { - if (fn == ".") - { - // A special case. - fn = relative_import_path; - } - else - fn = relative_import_path + '/' + fn; - is_local = false; - } - - if (!is_local) - { - for (std::vector<std::string>::const_iterator p = search_path.begin(); - p != search_path.end(); - ++p) - { - std::string indir = *p; - if (!indir.empty() && indir[indir.size() - 1] != '/') - indir += '/'; - indir += fn; - Stream* s = Import::try_package_in_directory(indir, location); - if (s != NULL) - return s; - } - } - - Stream* s = Import::try_package_in_directory(fn, location); - if (s != NULL) - return s; - - return NULL; -} - -// Try to find the export data for FILENAME. - -Import::Stream* -Import::try_package_in_directory(const std::string& filename, - Location location) -{ - std::string found_filename = filename; - int fd = open(found_filename.c_str(), O_RDONLY | O_BINARY); - - if (fd >= 0) - { - struct stat s; - if (fstat(fd, &s) >= 0 && S_ISDIR(s.st_mode)) - { - close(fd); - fd = -1; - errno = EISDIR; - } - } - - if (fd < 0) - { - if (errno != ENOENT && errno != EISDIR) - warning_at(location, 0, "%s: %m", filename.c_str()); - - fd = Import::try_suffixes(&found_filename); - if (fd < 0) - return NULL; - } - - // The export data may not be in this file. - Stream* s = Import::find_export_data(found_filename, fd, location); - if (s != NULL) - return s; - - close(fd); - - error_at(location, "%s exists but does not contain any Go export data", - found_filename.c_str()); - - return NULL; -} - -// Given import "*PFILENAME", where *PFILENAME does not exist, try -// various suffixes. If we find one, set *PFILENAME to the one we -// found. Return the open file descriptor. - -int -Import::try_suffixes(std::string* pfilename) -{ - std::string filename = *pfilename + ".gox"; - int fd = open(filename.c_str(), O_RDONLY | O_BINARY); - if (fd >= 0) - { - *pfilename = filename; - return fd; - } - - const char* basename = lbasename(pfilename->c_str()); - size_t basename_pos = basename - pfilename->c_str(); - filename = pfilename->substr(0, basename_pos) + "lib" + basename + ".so"; - fd = open(filename.c_str(), O_RDONLY | O_BINARY); - if (fd >= 0) - { - *pfilename = filename; - return fd; - } - - filename = pfilename->substr(0, basename_pos) + "lib" + basename + ".a"; - fd = open(filename.c_str(), O_RDONLY | O_BINARY); - if (fd >= 0) - { - *pfilename = filename; - return fd; - } - - filename = *pfilename + ".o"; - fd = open(filename.c_str(), O_RDONLY | O_BINARY); - if (fd >= 0) - { - *pfilename = filename; - return fd; - } - - return -1; -} - -// Look for export data in the file descriptor FD. - -Import::Stream* -Import::find_export_data(const std::string& filename, int fd, - Location location) -{ - // See if we can read this as an object file. - Import::Stream* stream = Import::find_object_export_data(filename, fd, 0, - location); - if (stream != NULL) - return stream; - - const int len = MAX(Export::v1_magic_len, Import::archive_magic_len); - - if (lseek(fd, 0, SEEK_SET) < 0) - { - error_at(location, "lseek %s failed: %m", filename.c_str()); - return NULL; - } - - char buf[len]; - ssize_t c = read(fd, buf, len); - if (c < len) - return NULL; - - // Check for a file containing nothing but Go export data. - if (memcmp(buf, Export::v1_magic, Export::v1_magic_len) == 0) - return new Stream_from_file(fd); - - // See if we can read this as an archive. - if (Import::is_archive_magic(buf)) - return Import::find_archive_export_data(filename, fd, location); - - return NULL; -} - -// Look for export data in a simple_object. - -Import::Stream* -Import::find_object_export_data(const std::string& filename, - int fd, - off_t offset, - Location location) -{ - char *buf; - size_t len; - int err; - const char *errmsg = go_read_export_data(fd, offset, &buf, &len, &err); - if (errmsg != NULL) - { - if (err == 0) - error_at(location, "%s: %s", filename.c_str(), errmsg); - else - error_at(location, "%s: %s: %s", filename.c_str(), errmsg, - xstrerror(err)); - return NULL; - } - - if (buf == NULL) - return NULL; - - return new Stream_from_buffer(buf, len); -} - -// Class Import. - -// Construct an Import object. We make the builtin_types_ vector -// large enough to hold all the builtin types. - -Import::Import(Stream* stream, Location location) - : gogo_(NULL), stream_(stream), location_(location), package_(NULL), - add_to_globals_(false), - builtin_types_((- SMALLEST_BUILTIN_CODE) + 1), - types_() -{ -} - -// Import the data in the associated stream. - -Package* -Import::import(Gogo* gogo, const std::string& local_name, - bool is_local_name_exported) -{ - // Hold on to the Gogo structure. Otherwise we need to pass it - // through all the import functions, because we need it when reading - // a type. - this->gogo_ = gogo; - - // A stream of export data can include data from more than one input - // file. Here we loop over each input file. - Stream* stream = this->stream_; - while (!stream->at_eof() && !stream->saw_error()) - { - // The vector of types is package specific. - this->types_.clear(); - - stream->require_bytes(this->location_, Export::v1_magic, - Export::v1_magic_len); - - this->require_c_string("package "); - std::string package_name = this->read_identifier(); - this->require_c_string(";\n"); - - std::string pkgpath; - if (this->match_c_string("prefix ")) - { - this->advance(7); - std::string unique_prefix = this->read_identifier(); - this->require_c_string(";\n"); - pkgpath = unique_prefix + '.' + package_name; - } - else - { - this->require_c_string("pkgpath "); - pkgpath = this->read_identifier(); - this->require_c_string(";\n"); - } - - this->package_ = gogo->add_imported_package(package_name, local_name, - is_local_name_exported, - pkgpath, - this->location_, - &this->add_to_globals_); - if (this->package_ == NULL) - { - stream->set_saw_error(); - return NULL; - } - - this->require_c_string("priority "); - std::string priority_string = this->read_identifier(); - int prio; - if (!this->string_to_int(priority_string, false, &prio)) - return NULL; - this->package_->set_priority(prio); - this->require_c_string(";\n"); - - while (stream->match_c_string("import")) - this->read_one_import(); - - if (stream->match_c_string("init")) - this->read_import_init_fns(gogo); - - // Loop over all the input data for this package. - while (!stream->saw_error()) - { - if (stream->match_c_string("const ")) - this->import_const(); - else if (stream->match_c_string("type ")) - this->import_type(); - else if (stream->match_c_string("var ")) - this->import_var(); - else if (stream->match_c_string("func ")) - this->import_func(this->package_); - else if (stream->match_c_string("checksum ")) - break; - else - { - error_at(this->location_, - ("error in import data at %d: " - "expected %<const%>, %<type%>, %<var%>, " - "%<func%>, or %<checksum%>"), - stream->pos()); - stream->set_saw_error(); - return NULL; - } - } - - // We currently ignore the checksum. In the future we could - // store the checksum somewhere in the generated object and then - // verify that the checksum matches at link time or at dynamic - // load time. - this->require_c_string("checksum "); - stream->advance(Export::v1_checksum_len * 2); - this->require_c_string(";\n"); - } - - return this->package_; -} - -// Read an import line. We don't actually care about these. - -void -Import::read_one_import() -{ - this->require_c_string("import "); - std::string package_name = this->read_identifier(); - this->require_c_string(" "); - std::string pkgpath = this->read_identifier(); - this->require_c_string(" \""); - Stream* stream = this->stream_; - while (stream->peek_char() != '"') - stream->advance(1); - this->require_c_string("\";\n"); - - Package* p = this->gogo_->register_package(pkgpath, - Linemap::unknown_location()); - p->set_package_name(package_name, this->location()); -} - -// Read the list of import control functions. - -void -Import::read_import_init_fns(Gogo* gogo) -{ - this->require_c_string("init"); - while (!this->match_c_string(";")) - { - this->require_c_string(" "); - std::string package_name = this->read_identifier(); - this->require_c_string(" "); - std::string init_name = this->read_identifier(); - this->require_c_string(" "); - std::string prio_string = this->read_identifier(); - int prio; - if (!this->string_to_int(prio_string, false, &prio)) - return; - gogo->add_import_init_fn(package_name, init_name, prio); - } - this->require_c_string(";\n"); -} - -// Import a constant. - -void -Import::import_const() -{ - std::string name; - Type* type; - Expression* expr; - Named_constant::import_const(this, &name, &type, &expr); - Typed_identifier tid(name, type, this->location_); - Named_object* no = this->package_->add_constant(tid, expr); - if (this->add_to_globals_) - this->gogo_->add_named_object(no); -} - -// Import a type. - -void -Import::import_type() -{ - Named_type* type; - Named_type::import_named_type(this, &type); - - // The named type has been added to the package by the type import - // process. Here we need to make it visible to the parser, and it - // to the global bindings if necessary. - type->set_is_visible(); - - if (this->add_to_globals_) - this->gogo_->add_named_type(type); -} - -// Import a variable. - -void -Import::import_var() -{ - std::string name; - Type* type; - Variable::import_var(this, &name, &type); - Variable* var = new Variable(type, NULL, true, false, false, - this->location_); - Named_object* no; - no = this->package_->add_variable(name, var); - if (this->add_to_globals_) - this->gogo_->add_named_object(no); -} - -// Import a function into PACKAGE. PACKAGE is normally -// THIS->PACKAGE_, but it will be different for a method associated -// with a type defined in a different package. - -Named_object* -Import::import_func(Package* package) -{ - std::string name; - Typed_identifier* receiver; - Typed_identifier_list* parameters; - Typed_identifier_list* results; - bool is_varargs; - Function::import_func(this, &name, &receiver, ¶meters, &results, - &is_varargs); - Function_type *fntype = Type::make_function_type(receiver, parameters, - results, this->location_); - if (is_varargs) - fntype->set_is_varargs(); - - Location loc = this->location_; - Named_object* no; - if (fntype->is_method()) - { - Type* rtype = receiver->type(); - - // We may still be reading the definition of RTYPE, so we have - // to be careful to avoid calling base or convert. If RTYPE is - // a named type or a forward declaration, then we know that it - // is not a pointer, because we are reading a method on RTYPE - // and named pointers can't have methods. - - if (rtype->classification() == Type::TYPE_POINTER) - rtype = rtype->points_to(); - - if (rtype->is_error_type()) - return NULL; - else if (rtype->named_type() != NULL) - no = rtype->named_type()->add_method_declaration(name, package, fntype, - loc); - else if (rtype->forward_declaration_type() != NULL) - no = rtype->forward_declaration_type()->add_method_declaration(name, - package, - fntype, - loc); - else - go_unreachable(); - } - else - { - no = package->add_function_declaration(name, fntype, loc); - if (this->add_to_globals_) - this->gogo_->add_named_object(no); - } - return no; -} - -// Read a type in the import stream. This records the type by the -// type index. If the type is named, it registers the name, but marks -// it as invisible. - -Type* -Import::read_type() -{ - Stream* stream = this->stream_; - this->require_c_string("<type "); - - std::string number; - int c; - while (true) - { - c = stream->get_char(); - if (c != '-' && (c < '0' || c > '9')) - break; - number += c; - } - - int index; - if (!this->string_to_int(number, true, &index)) - return Type::make_error_type(); - - if (c == '>') - { - // This type was already defined. - if (index < 0 - ? (static_cast<size_t>(- index) >= this->builtin_types_.size() - || this->builtin_types_[- index] == NULL) - : (static_cast<size_t>(index) >= this->types_.size() - || this->types_[index] == NULL)) - { - error_at(this->location_, - "error in import data at %d: bad type index %d", - stream->pos(), index); - stream->set_saw_error(); - return Type::make_error_type(); - } - - return index < 0 ? this->builtin_types_[- index] : this->types_[index]; - } - - if (c != ' ') - { - if (!stream->saw_error()) - error_at(this->location_, - "error in import data at %d: expect %< %> or %<>%>'", - stream->pos()); - stream->set_saw_error(); - stream->advance(1); - return Type::make_error_type(); - } - - if (index <= 0 - || (static_cast<size_t>(index) < this->types_.size() - && this->types_[index] != NULL)) - { - error_at(this->location_, - "error in import data at %d: type index already defined", - stream->pos()); - stream->set_saw_error(); - return Type::make_error_type(); - } - - if (static_cast<size_t>(index) >= this->types_.size()) - { - int newsize = std::max(static_cast<size_t>(index) + 1, - this->types_.size() * 2); - this->types_.resize(newsize, NULL); - } - - if (stream->peek_char() != '"') - { - Type* type = Type::import_type(this); - this->require_c_string(">"); - this->types_[index] = type; - return type; - } - - // This type has a name. - - stream->advance(1); - std::string type_name; - while ((c = stream->get_char()) != '"') - type_name += c; - - // If this type is in the package we are currently importing, the - // name will be .PKGPATH.NAME or simply NAME with no dots. - // Otherwise, a non-hidden symbol will be PKGPATH.NAME and a hidden - // symbol will be .PKGPATH.NAME. - std::string pkgpath; - if (type_name.find('.') != std::string::npos) - { - size_t start = 0; - if (type_name[0] == '.') - start = 1; - size_t dot = type_name.rfind('.'); - pkgpath = type_name.substr(start, dot - start); - if (type_name[0] != '.') - type_name.erase(0, dot + 1); - } - - this->require_c_string(" "); - - // The package name may follow. This is the name of the package in - // the package clause of that package. The type name will include - // the pkgpath, which may be different. - std::string package_name; - if (stream->peek_char() == '"') - { - stream->advance(1); - while ((c = stream->get_char()) != '"') - package_name += c; - this->require_c_string(" "); - } - - // Declare the type in the appropriate package. If we haven't seen - // it before, mark it as invisible. We declare it before we read - // the actual definition of the type, since the definition may refer - // to the type itself. - Package* package; - if (pkgpath.empty() || pkgpath == this->gogo_->pkgpath()) - package = this->package_; - else - { - package = this->gogo_->register_package(pkgpath, - Linemap::unknown_location()); - if (!package_name.empty()) - package->set_package_name(package_name, this->location()); - } - - Named_object* no = package->bindings()->lookup(type_name); - if (no == NULL) - no = package->add_type_declaration(type_name, this->location_); - else if (!no->is_type_declaration() && !no->is_type()) - { - error_at(this->location_, "imported %<%s.%s%> both type and non-type", - pkgpath.c_str(), Gogo::message_name(type_name).c_str()); - stream->set_saw_error(); - return Type::make_error_type(); - } - else - go_assert(no->package() == package); - - if (this->types_[index] == NULL) - { - if (no->is_type_declaration()) - { - // FIXME: It's silly to make a forward declaration every time. - this->types_[index] = Type::make_forward_declaration(no); - } - else - { - go_assert(no->is_type()); - this->types_[index] = no->type_value(); - } - } - - // If there is no type definition, then this is just a forward - // declaration of a type defined in some other file. - Type* type; - if (this->match_c_string(">")) - type = this->types_[index]; - else - { - type = this->read_type(); - - if (no->is_type_declaration()) - { - // We can define the type now. - - no = package->add_type(type_name, type, this->location_); - Named_type* ntype = no->type_value(); - - // This type has not yet been imported. - ntype->clear_is_visible(); - - if (!type->is_undefined() && type->interface_type() != NULL) - this->gogo_->record_interface_type(type->interface_type()); - - type = ntype; - } - else if (no->is_type()) - { - // We have seen this type before. FIXME: it would be a good - // idea to check that the two imported types are identical, - // but we have not finalized the methods yet, which means - // that we can not reliably compare interface types. - type = no->type_value(); - - // Don't change the visibility of the existing type. - } - - this->types_[index] = type; - - // Read the type methods. - if (this->match_c_string("\n")) - { - this->advance(1); - while (this->match_c_string(" func")) - { - this->advance(1); - this->import_func(package); - } - } - } - - this->require_c_string(">"); - - return type; -} - -// Register the builtin types. - -void -Import::register_builtin_types(Gogo* gogo) -{ - this->register_builtin_type(gogo, "int8", BUILTIN_INT8); - this->register_builtin_type(gogo, "int16", BUILTIN_INT16); - this->register_builtin_type(gogo, "int32", BUILTIN_INT32); - this->register_builtin_type(gogo, "int64", BUILTIN_INT64); - this->register_builtin_type(gogo, "uint8", BUILTIN_UINT8); - this->register_builtin_type(gogo, "uint16", BUILTIN_UINT16); - this->register_builtin_type(gogo, "uint32", BUILTIN_UINT32); - this->register_builtin_type(gogo, "uint64", BUILTIN_UINT64); - this->register_builtin_type(gogo, "float32", BUILTIN_FLOAT32); - this->register_builtin_type(gogo, "float64", BUILTIN_FLOAT64); - this->register_builtin_type(gogo, "complex64", BUILTIN_COMPLEX64); - this->register_builtin_type(gogo, "complex128", BUILTIN_COMPLEX128); - this->register_builtin_type(gogo, "int", BUILTIN_INT); - this->register_builtin_type(gogo, "uint", BUILTIN_UINT); - this->register_builtin_type(gogo, "uintptr", BUILTIN_UINTPTR); - this->register_builtin_type(gogo, "bool", BUILTIN_BOOL); - this->register_builtin_type(gogo, "string", BUILTIN_STRING); - this->register_builtin_type(gogo, "error", BUILTIN_ERROR); - this->register_builtin_type(gogo, "byte", BUILTIN_BYTE); - this->register_builtin_type(gogo, "rune", BUILTIN_RUNE); -} - -// Register a single builtin type. - -void -Import::register_builtin_type(Gogo* gogo, const char* name, Builtin_code code) -{ - Named_object* named_object = gogo->lookup_global(name); - go_assert(named_object != NULL && named_object->is_type()); - int index = - static_cast<int>(code); - go_assert(index > 0 - && static_cast<size_t>(index) < this->builtin_types_.size()); - this->builtin_types_[index] = named_object->type_value(); -} - -// Read an identifier from the stream. - -std::string -Import::read_identifier() -{ - std::string ret; - Stream* stream = this->stream_; - int c; - while (true) - { - c = stream->peek_char(); - if (c == -1 || c == ' ' || c == ';') - break; - ret += c; - stream->advance(1); - } - return ret; -} - -// Read a name from the stream. - -std::string -Import::read_name() -{ - std::string ret = this->read_identifier(); - if (ret == "?") - ret.clear(); - else if (!Lex::is_exported_name(ret)) - ret = '.' + this->package_->pkgpath() + '.' + ret; - return ret; -} - -// Turn a string into a integer with appropriate error handling. - -bool -Import::string_to_int(const std::string &s, bool is_neg_ok, int* ret) -{ - char* end; - long prio = strtol(s.c_str(), &end, 10); - if (*end != '\0' || prio > 0x7fffffff || (prio < 0 && !is_neg_ok)) - { - error_at(this->location_, "invalid integer in import data at %d", - this->stream_->pos()); - this->stream_->set_saw_error(); - return false; - } - *ret = prio; - return true; -} - -// Class Import::Stream. - -Import::Stream::Stream() - : pos_(0), saw_error_(false) -{ -} - -Import::Stream::~Stream() -{ -} - -// Return the next character to come from the stream. - -int -Import::Stream::peek_char() -{ - const char* read; - if (!this->do_peek(1, &read)) - return -1; - // Make sure we return an unsigned char, so that we don't get - // confused by \xff. - unsigned char ret = *read; - return ret; -} - -// Return true if the next LENGTH characters from the stream match -// BYTES - -bool -Import::Stream::match_bytes(const char* bytes, size_t length) -{ - const char* read; - if (!this->do_peek(length, &read)) - return false; - return memcmp(bytes, read, length) == 0; -} - -// Require that the next LENGTH bytes from the stream match BYTES. - -void -Import::Stream::require_bytes(Location location, const char* bytes, - size_t length) -{ - const char* read; - if (!this->do_peek(length, &read) - || memcmp(bytes, read, length) != 0) - { - if (!this->saw_error_) - error_at(location, "import error at %d: expected %<%.*s%>", - this->pos(), static_cast<int>(length), bytes); - this->saw_error_ = true; - return; - } - this->advance(length); -} - -// Class Stream_from_file. - -Stream_from_file::Stream_from_file(int fd) - : fd_(fd), data_() -{ - if (lseek(fd, 0, SEEK_SET) != 0) - { - error("lseek failed: %m"); - this->set_saw_error(); - } -} - -Stream_from_file::~Stream_from_file() -{ - close(this->fd_); -} - -// Read next bytes. - -bool -Stream_from_file::do_peek(size_t length, const char** bytes) -{ - if (this->data_.length() <= length) - { - *bytes = this->data_.data(); - return true; - } - // Don't bother to handle the general case, since we don't need it. - go_assert(length < 64); - char buf[64]; - ssize_t got = read(this->fd_, buf, length); - - if (got < 0) - { - if (!this->saw_error()) - error("read failed: %m"); - this->set_saw_error(); - return false; - } - - if (lseek(this->fd_, - got, SEEK_CUR) != 0) - { - if (!this->saw_error()) - error("lseek failed: %m"); - this->set_saw_error(); - return false; - } - - if (static_cast<size_t>(got) < length) - return false; - - this->data_.assign(buf, got); - - *bytes = this->data_.data(); - return true; -} - -// Advance. - -void -Stream_from_file::do_advance(size_t skip) -{ - if (lseek(this->fd_, skip, SEEK_CUR) != 0) - { - if (!this->saw_error()) - error("lseek failed: %m"); - this->set_saw_error(); - } - if (!this->data_.empty()) - { - if (this->data_.length() < skip) - this->data_.erase(0, skip); - else - this->data_.clear(); - } -} diff --git a/gcc-4.8.1/gcc/go/gofrontend/import.h b/gcc-4.8.1/gcc/go/gofrontend/import.h deleted file mode 100644 index c6844cda8..000000000 --- a/gcc-4.8.1/gcc/go/gofrontend/import.h +++ /dev/null @@ -1,359 +0,0 @@ -// import.h -- Go frontend import declarations. -*- C++ -*- - -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#ifndef GO_IMPORT_H -#define GO_IMPORT_H - -#include "export.h" -#include "go-linemap.h" - -class Gogo; -class Package; -class Type; -class Named_object; -class Named_type; -class Expression; - -// This class manages importing Go declarations. - -class Import -{ - public: - // The Stream class is an interface used to read the data. The - // caller should instantiate a child of this class. - class Stream - { - public: - Stream(); - virtual ~Stream(); - - // Return whether we have seen an error. - bool - saw_error() const - { return this->saw_error_; } - - // Record that we've seen an error. - void - set_saw_error() - { this->saw_error_ = true; } - - // Return the next character (a value from 0 to 0xff) without - // advancing. Returns -1 at end of stream. - int - peek_char(); - - // Look for LENGTH characters, setting *BYTES to point to them. - // Returns false if the bytes are not available. Does not - // advance. - bool - peek(size_t length, const char** bytes) - { return this->do_peek(length, bytes); } - - // Return the next character (a value from 0 to 0xff) and advance - // the read position by 1. Returns -1 at end of stream. - int - get_char() - { - int c = this->peek_char(); - this->advance(1); - return c; - } - - // Return true if at the end of the stream. - bool - at_eof() - { return this->peek_char() == -1; } - - // Return true if the next bytes match STR. - bool - match_c_string(const char* str) - { return this->match_bytes(str, strlen(str)); } - - // Return true if the next LENGTH bytes match BYTES. - bool - match_bytes(const char* bytes, size_t length); - - // Give an error if the next bytes do not match STR. Advance the - // read position by the length of STR. - void - require_c_string(Location location, const char* str) - { this->require_bytes(location, str, strlen(str)); } - - // Given an error if the next LENGTH bytes do not match BYTES. - // Advance the read position by LENGTH. - void - require_bytes(Location, const char* bytes, size_t length); - - // Advance the read position by SKIP bytes. - void - advance(size_t skip) - { - this->do_advance(skip); - this->pos_ += skip; - } - - // Return the current read position. This returns int because it - // is more convenient in error reporting. FIXME. - int - pos() - { return static_cast<int>(this->pos_); } - - protected: - // This function should set *BYTES to point to a buffer holding - // the LENGTH bytes at the current read position. It should - // return false if the bytes are not available. This should not - // change the current read position. - virtual bool - do_peek(size_t length, const char** bytes) = 0; - - // This function should advance the current read position LENGTH - // bytes. - virtual void - do_advance(size_t skip) = 0; - - private: - // The current read position. - size_t pos_; - // True if we've seen an error reading from this stream. - bool saw_error_; - }; - - // Find import data. This searches the file system for FILENAME and - // returns a pointer to a Stream object to read the data that it - // exports. LOCATION is the location of the import statement. - // RELATIVE_IMPORT_PATH is used as a prefix for a relative import. - static Stream* - open_package(const std::string& filename, Location location, - const std::string& relative_import_path); - - // Constructor. - Import(Stream*, Location); - - // Register the builtin types. - void - register_builtin_types(Gogo*); - - // Import everything defined in the stream. LOCAL_NAME is the local - // name to be used for bindings; if it is the string "." then - // bindings should be inserted in the global scope. If LOCAL_NAME - // is the empty string then the name of the package itself is the - // local name. This returns the imported package, or NULL on error. - Package* - import(Gogo*, const std::string& local_name, bool is_local_name_exported); - - // The location of the import statement. - Location - location() const - { return this->location_; } - - // Return the next character. - int - peek_char() - { return this->stream_->peek_char(); } - - // Return the next character and advance. - int - get_char() - { return this->stream_->get_char(); } - - // Return true at the end of the stream. - bool - at_eof() - { return this->stream_->at_eof(); } - - // Return whether the next bytes match STR. - bool - match_c_string(const char* str) - { return this->stream_->match_c_string(str); } - - // Require that the next bytes match STR. - void - require_c_string(const char* str) - { this->stream_->require_c_string(this->location_, str); } - - // Advance the stream SKIP bytes. - void - advance(size_t skip) - { this->stream_->advance(skip); } - - // Read an identifier. - std::string - read_identifier(); - - // Read a name. This is like read_identifier, except that a "?" is - // returned as an empty string. This matches Export::write_name. - std::string - read_name(); - - // Read a type. - Type* - read_type(); - - private: - static Stream* - try_package_in_directory(const std::string&, Location); - - static int - try_suffixes(std::string*); - - static Stream* - find_export_data(const std::string& filename, int fd, Location); - - static Stream* - find_object_export_data(const std::string& filename, int fd, - off_t offset, Location); - - static const int archive_magic_len = 8; - - static bool - is_archive_magic(const char*); - - static Stream* - find_archive_export_data(const std::string& filename, int fd, - Location); - - // Read an import line. - void - read_one_import(); - - // Read the import control functions. - void - read_import_init_fns(Gogo*); - - // Import a constant. - void - import_const(); - - // Import a type. - void - import_type(); - - // Import a variable. - void - import_var(); - - // Import a function. - Named_object* - import_func(Package*); - - // Register a single builtin type. - void - register_builtin_type(Gogo*, const char* name, Builtin_code); - - // Get an integer from a string. - bool - string_to_int(const std::string&, bool is_neg_ok, int* ret); - - // The general IR. - Gogo* gogo_; - // The stream from which to read import data. - Stream* stream_; - // The location of the import statement we are processing. - Location location_; - // The package we are importing. - Package* package_; - // Whether to add new objects to the global scope, rather than to a - // package scope. - bool add_to_globals_; - // Mapping from negated builtin type codes to Type structures. - std::vector<Named_type*> builtin_types_; - // Mapping from exported type codes to Type structures. - std::vector<Type*> types_; -}; - -// Read import data from a string. - -class Stream_from_string : public Import::Stream -{ - public: - Stream_from_string(const std::string& str) - : str_(str), pos_(0) - { } - - protected: - bool - do_peek(size_t length, const char** bytes) - { - if (this->pos_ + length > this->str_.length()) - return false; - *bytes = this->str_.data() + this->pos_; - return true; - } - - void - do_advance(size_t len) - { this->pos_ += len; } - - private: - // The string of data we are reading. - std::string str_; - // The current position within the string. - size_t pos_; -}; - -// Read import data from a buffer allocated using malloc. - -class Stream_from_buffer : public Import::Stream -{ - public: - Stream_from_buffer(char* buf, size_t length) - : buf_(buf), length_(length), pos_(0) - { } - - ~Stream_from_buffer() - { free(this->buf_); } - - protected: - bool - do_peek(size_t length, const char** bytes) - { - if (this->pos_ + length > this->length_) - return false; - *bytes = this->buf_ + this->pos_; - return true; - } - - void - do_advance(size_t len) - { this->pos_ += len; } - - private: - // The data we are reading. - char* buf_; - // The length of the buffer. - size_t length_; - // The current position within the buffer. - size_t pos_; -}; - -// Read import data from an open file descriptor. - -class Stream_from_file : public Import::Stream -{ - public: - Stream_from_file(int fd); - - ~Stream_from_file(); - - protected: - bool - do_peek(size_t, const char**); - - void - do_advance(size_t); - - private: - // No copying. - Stream_from_file(const Stream_from_file&); - Stream_from_file& operator=(const Stream_from_file&); - - // The file descriptor. - int fd_; - // Data read from the file. - std::string data_; -}; - -#endif // !defined(GO_IMPORT_H) diff --git a/gcc-4.8.1/gcc/go/gofrontend/lex.cc b/gcc-4.8.1/gcc/go/gofrontend/lex.cc deleted file mode 100644 index 22a1f6e2a..000000000 --- a/gcc-4.8.1/gcc/go/gofrontend/lex.cc +++ /dev/null @@ -1,2419 +0,0 @@ -// lex.cc -- Go frontend lexer. - -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "go-system.h" - -#include "lex.h" - -// Manage mapping from keywords to the Keyword codes. - -class Keywords -{ - public: - // The structure which maps keywords to codes. - struct Mapping - { - // Keyword string. - const char* keystring; - // Keyword code. - Keyword keycode; - }; - - // Return the parsecode corresponding to KEYSTRING, or - // KEYWORD_INVALID if it is not a keyword. - Keyword - keyword_to_code(const char* keyword, size_t len) const; - - // Return the string for a keyword. - const char* - keyword_to_string(Keyword) const; - - private: - static const Mapping mapping_[]; - static const int count_; -}; - -// Mapping from keyword string to keyword code. This array must be -// kept in sorted order, and the order must match the Keyword enum. -// Strings are looked up using bsearch. - -const Keywords::Mapping -Keywords::mapping_[] = -{ - { NULL, KEYWORD_INVALID }, - { "__asm__", KEYWORD_ASM }, - { "break", KEYWORD_BREAK }, - { "case", KEYWORD_CASE }, - { "chan", KEYWORD_CHAN }, - { "const", KEYWORD_CONST }, - { "continue", KEYWORD_CONTINUE }, - { "default", KEYWORD_DEFAULT }, - { "defer", KEYWORD_DEFER }, - { "else", KEYWORD_ELSE }, - { "fallthrough", KEYWORD_FALLTHROUGH }, - { "for", KEYWORD_FOR }, - { "func", KEYWORD_FUNC }, - { "go", KEYWORD_GO }, - { "goto", KEYWORD_GOTO }, - { "if", KEYWORD_IF }, - { "import", KEYWORD_IMPORT }, - { "interface", KEYWORD_INTERFACE }, - { "map", KEYWORD_MAP }, - { "package", KEYWORD_PACKAGE }, - { "range", KEYWORD_RANGE }, - { "return", KEYWORD_RETURN }, - { "select", KEYWORD_SELECT }, - { "struct", KEYWORD_STRUCT }, - { "switch", KEYWORD_SWITCH }, - { "type", KEYWORD_TYPE }, - { "var", KEYWORD_VAR } -}; - -// Number of entries in the map. - -const int Keywords::count_ = - sizeof(Keywords::mapping_) / sizeof(Keywords::mapping_[0]); - -// Comparison function passed to bsearch. - -extern "C" -{ - -struct Keywords_search_key -{ - const char* str; - size_t len; -}; - -static int -keyword_compare(const void* keyv, const void* mapv) -{ - const Keywords_search_key* key = - static_cast<const Keywords_search_key*>(keyv); - const Keywords::Mapping* map = - static_cast<const Keywords::Mapping*>(mapv); - if (map->keystring == NULL) - return 1; - int i = strncmp(key->str, map->keystring, key->len); - if (i != 0) - return i; - if (map->keystring[key->len] != '\0') - return -1; - return 0; -} - -} // End extern "C". - -// Convert a string to a keyword code. Return KEYWORD_INVALID if the -// string is not a keyword. - -Keyword -Keywords::keyword_to_code(const char* keyword, size_t len) const -{ - Keywords_search_key key; - key.str = keyword; - key.len = len; - void* mapv = bsearch(&key, - this->mapping_, - this->count_, - sizeof(this->mapping_[0]), - keyword_compare); - if (mapv == NULL) - return KEYWORD_INVALID; - Mapping* map = static_cast<Mapping*>(mapv); - return map->keycode; -} - -// Convert a keyword code to a string. - -const char* -Keywords::keyword_to_string(Keyword code) const -{ - go_assert(code > KEYWORD_INVALID && code < this->count_); - const Mapping* map = &this->mapping_[code]; - go_assert(map->keycode == code); - return map->keystring; -} - -// There is one instance of the Keywords class. - -static Keywords keywords; - -// Class Token. - -// Make a general token. - -Token::Token(Classification classification, Location location) - : classification_(classification), location_(location) -{ -} - -// Destroy a token. - -Token::~Token() -{ - this->clear(); -} - -// Clear a token--release memory. - -void -Token::clear() -{ - if (this->classification_ == TOKEN_INTEGER - || this->classification_ == TOKEN_CHARACTER) - mpz_clear(this->u_.integer_value); - else if (this->classification_ == TOKEN_FLOAT - || this->classification_ == TOKEN_IMAGINARY) - mpfr_clear(this->u_.float_value); -} - -// Construct a token. - -Token::Token(const Token& tok) - : classification_(tok.classification_), location_(tok.location_) -{ - switch (this->classification_) - { - case TOKEN_INVALID: - case TOKEN_EOF: - break; - case TOKEN_KEYWORD: - this->u_.keyword = tok.u_.keyword; - break; - case TOKEN_IDENTIFIER: - case TOKEN_STRING: - this->u_.string_value = tok.u_.string_value; - break; - case TOKEN_OPERATOR: - this->u_.op = tok.u_.op; - break; - case TOKEN_CHARACTER: - case TOKEN_INTEGER: - mpz_init_set(this->u_.integer_value, tok.u_.integer_value); - break; - case TOKEN_FLOAT: - case TOKEN_IMAGINARY: - mpfr_init_set(this->u_.float_value, tok.u_.float_value, GMP_RNDN); - break; - default: - go_unreachable(); - } -} - -// Assign to a token. - -Token& -Token::operator=(const Token& tok) -{ - this->clear(); - this->classification_ = tok.classification_; - this->location_ = tok.location_; - switch (tok.classification_) - { - case TOKEN_INVALID: - case TOKEN_EOF: - break; - case TOKEN_KEYWORD: - this->u_.keyword = tok.u_.keyword; - break; - case TOKEN_IDENTIFIER: - this->u_.identifier_value.name = tok.u_.identifier_value.name; - this->u_.identifier_value.is_exported = - tok.u_.identifier_value.is_exported; - break; - case TOKEN_STRING: - this->u_.string_value = tok.u_.string_value; - break; - case TOKEN_OPERATOR: - this->u_.op = tok.u_.op; - break; - case TOKEN_CHARACTER: - case TOKEN_INTEGER: - mpz_init_set(this->u_.integer_value, tok.u_.integer_value); - break; - case TOKEN_FLOAT: - case TOKEN_IMAGINARY: - mpfr_init_set(this->u_.float_value, tok.u_.float_value, GMP_RNDN); - break; - default: - go_unreachable(); - } - return *this; -} - -// Print the token for debugging. - -void -Token::print(FILE* file) const -{ - switch (this->classification_) - { - case TOKEN_INVALID: - fprintf(file, "invalid"); - break; - case TOKEN_EOF: - fprintf(file, "EOF"); - break; - case TOKEN_KEYWORD: - fprintf(file, "keyword %s", keywords.keyword_to_string(this->u_.keyword)); - break; - case TOKEN_IDENTIFIER: - fprintf(file, "identifier \"%s\"", this->u_.string_value->c_str()); - break; - case TOKEN_STRING: - fprintf(file, "quoted string \"%s\"", this->u_.string_value->c_str()); - break; - case TOKEN_CHARACTER: - fprintf(file, "character "); - mpz_out_str(file, 10, this->u_.integer_value); - break; - case TOKEN_INTEGER: - fprintf(file, "integer "); - mpz_out_str(file, 10, this->u_.integer_value); - break; - case TOKEN_FLOAT: - fprintf(file, "float "); - mpfr_out_str(file, 10, 0, this->u_.float_value, GMP_RNDN); - break; - case TOKEN_IMAGINARY: - fprintf(file, "imaginary "); - mpfr_out_str(file, 10, 0, this->u_.float_value, GMP_RNDN); - break; - case TOKEN_OPERATOR: - fprintf(file, "operator "); - switch (this->u_.op) - { - case OPERATOR_INVALID: - fprintf(file, "invalid"); - break; - case OPERATOR_OROR: - fprintf(file, "||"); - break; - case OPERATOR_ANDAND: - fprintf(file, "&&"); - break; - case OPERATOR_EQEQ: - fprintf(file, "=="); - break; - case OPERATOR_NOTEQ: - fprintf(file, "!="); - break; - case OPERATOR_LT: - fprintf(file, "<"); - break; - case OPERATOR_LE: - fprintf(file, "<="); - break; - case OPERATOR_GT: - fprintf(file, ">"); - break; - case OPERATOR_GE: - fprintf(file, ">="); - break; - case OPERATOR_PLUS: - fprintf(file, "+"); - break; - case OPERATOR_MINUS: - fprintf(file, "-"); - break; - case OPERATOR_OR: - fprintf(file, "|"); - break; - case OPERATOR_XOR: - fprintf(file, "^"); - break; - case OPERATOR_MULT: - fprintf(file, "*"); - break; - case OPERATOR_DIV: - fprintf(file, "/"); - break; - case OPERATOR_MOD: - fprintf(file, "%%"); - break; - case OPERATOR_LSHIFT: - fprintf(file, "<<"); - break; - case OPERATOR_RSHIFT: - fprintf(file, ">>"); - break; - case OPERATOR_AND: - fprintf(file, "&"); - break; - case OPERATOR_BITCLEAR: - fprintf(file, "&^"); - break; - case OPERATOR_NOT: - fprintf(file, "!"); - break; - case OPERATOR_CHANOP: - fprintf(file, "<-"); - break; - case OPERATOR_EQ: - fprintf(file, "="); - break; - case OPERATOR_PLUSEQ: - fprintf(file, "+="); - break; - case OPERATOR_MINUSEQ: - fprintf(file, "-="); - break; - case OPERATOR_OREQ: - fprintf(file, "|="); - break; - case OPERATOR_XOREQ: - fprintf(file, "^="); - break; - case OPERATOR_MULTEQ: - fprintf(file, "*="); - break; - case OPERATOR_DIVEQ: - fprintf(file, "/="); - break; - case OPERATOR_MODEQ: - fprintf(file, "%%="); - break; - case OPERATOR_LSHIFTEQ: - fprintf(file, "<<="); - break; - case OPERATOR_RSHIFTEQ: - fprintf(file, ">>="); - break; - case OPERATOR_ANDEQ: - fprintf(file, "&="); - break; - case OPERATOR_BITCLEAREQ: - fprintf(file, "&^="); - break; - case OPERATOR_PLUSPLUS: - fprintf(file, "++"); - break; - case OPERATOR_MINUSMINUS: - fprintf(file, "--"); - break; - case OPERATOR_COLON: - fprintf(file, ":"); - break; - case OPERATOR_COLONEQ: - fprintf(file, ":="); - break; - case OPERATOR_SEMICOLON: - fprintf(file, ";"); - break; - case OPERATOR_DOT: - fprintf(file, "."); - break; - case OPERATOR_COMMA: - fprintf(file, ","); - break; - case OPERATOR_LPAREN: - fprintf(file, "("); - break; - case OPERATOR_RPAREN: - fprintf(file, ")"); - break; - case OPERATOR_LCURLY: - fprintf(file, "{"); - break; - case OPERATOR_RCURLY: - fprintf(file, "}"); - break; - case OPERATOR_LSQUARE: - fprintf(file, "["); - break; - case OPERATOR_RSQUARE: - fprintf(file, "]"); - break; - default: - go_unreachable(); - } - break; - default: - go_unreachable(); - } -} - -// Class Lex. - -Lex::Lex(const char* input_file_name, FILE* input_file, Linemap* linemap) - : input_file_name_(input_file_name), input_file_(input_file), - linemap_(linemap), linebuf_(NULL), linebufsize_(120), linesize_(0), - lineoff_(0), lineno_(0), add_semi_at_eol_(false), saw_nointerface_(false), - extern_() -{ - this->linebuf_ = new char[this->linebufsize_]; - this->linemap_->start_file(input_file_name, 0); -} - -Lex::~Lex() -{ - delete[] this->linebuf_; -} - -// Read a new line from the file. - -ssize_t -Lex::get_line() -{ - char* buf = this->linebuf_; - size_t size = this->linebufsize_; - - FILE* file = this->input_file_; - size_t cur = 0; - while (true) - { - int c = getc(file); - if (c == EOF) - { - if (cur == 0) - return -1; - break; - } - if (cur + 1 >= size) - { - size_t ns = 2 * size + 1; - if (ns < size || static_cast<ssize_t>(ns) < 0) - error_at(this->location(), "out of memory"); - char* nb = new char[ns]; - memcpy(nb, buf, cur); - delete[] buf; - buf = nb; - size = ns; - } - buf[cur] = c; - ++cur; - - if (c == '\n') - break; - } - - buf[cur] = '\0'; - - this->linebuf_ = buf; - this->linebufsize_ = size; - - return cur; -} - -// See if we need to read a new line. Return true if there is a new -// line, false if we are at EOF. - -bool -Lex::require_line() -{ - if (this->lineoff_ < this->linesize_) - return true; - - ssize_t got = this->get_line(); - if (got < 0) - return false; - ++this->lineno_; - this->linesize_= got; - this->lineoff_ = 0; - - this->linemap_->start_line(this->lineno_, this->linesize_); - - return true; -} - -// Get the current location. - -Location -Lex::location() const -{ - return this->linemap_->get_location(this->lineoff_ + 1); -} - -// Get a location slightly before the current one. This is used for -// slightly more efficient handling of operator tokens. - -Location -Lex::earlier_location(int chars) const -{ - return this->linemap_->get_location(this->lineoff_ + 1 - chars); -} - -// Get the next token. - -Token -Lex::next_token() -{ - bool saw_cpp_comment = false; - while (true) - { - if (!this->require_line()) - { - bool add_semi_at_eol = this->add_semi_at_eol_; - this->add_semi_at_eol_ = false; - if (add_semi_at_eol) - return this->make_operator(OPERATOR_SEMICOLON, 1); - return this->make_eof_token(); - } - - if (!saw_cpp_comment) - this->extern_.clear(); - saw_cpp_comment = false; - - const char* p = this->linebuf_ + this->lineoff_; - const char* pend = this->linebuf_ + this->linesize_; - - while (p < pend) - { - unsigned char cc = *p; - switch (cc) - { - case ' ': case '\t': case '\r': - ++p; - // Skip whitespace quickly. - while (*p == ' ' || *p == '\t' || *p == '\r') - ++p; - break; - - case '\n': - { - ++p; - bool add_semi_at_eol = this->add_semi_at_eol_; - this->add_semi_at_eol_ = false; - if (add_semi_at_eol) - { - this->lineoff_ = p - this->linebuf_; - return this->make_operator(OPERATOR_SEMICOLON, 1); - } - } - break; - - case '/': - if (p[1] == '/') - { - this->lineoff_ = p + 2 - this->linebuf_; - this->skip_cpp_comment(); - p = pend; - if (p[-1] == '\n' && this->add_semi_at_eol_) - --p; - saw_cpp_comment = true; - } - else if (p[1] == '*') - { - this->lineoff_ = p - this->linebuf_; - Location location = this->location(); - if (!this->skip_c_comment()) - return Token::make_invalid_token(location); - p = this->linebuf_ + this->lineoff_; - pend = this->linebuf_ + this->linesize_; - } - else if (p[1] == '=') - { - this->add_semi_at_eol_ = false; - this->lineoff_ = p + 2 - this->linebuf_; - return this->make_operator(OPERATOR_DIVEQ, 2); - } - else - { - this->add_semi_at_eol_ = false; - this->lineoff_ = p + 1 - this->linebuf_; - return this->make_operator(OPERATOR_DIV, 1); - } - break; - - case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': - case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': - case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': - case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': - case 'Y': case 'Z': - case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': - case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': - case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': - case 's': case 't': case 'u': case 'v': case 'w': case 'x': - case 'y': case 'z': - case '_': - this->lineoff_ = p - this->linebuf_; - return this->gather_identifier(); - - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - this->add_semi_at_eol_ = true; - this->lineoff_ = p - this->linebuf_; - return this->gather_number(); - - case '\'': - this->add_semi_at_eol_ = true; - this->lineoff_ = p - this->linebuf_; - return this->gather_character(); - - case '"': - this->add_semi_at_eol_ = true; - this->lineoff_ = p - this->linebuf_; - return this->gather_string(); - - case '`': - this->add_semi_at_eol_ = true; - this->lineoff_ = p - this->linebuf_; - return this->gather_raw_string(); - - case '<': - case '>': - case '&': - if (p + 2 < pend) - { - this->add_semi_at_eol_ = false; - Operator op = this->three_character_operator(cc, p[1], p[2]); - if (op != OPERATOR_INVALID) - { - this->lineoff_ = p + 3 - this->linebuf_; - return this->make_operator(op, 3); - } - } - // Fall through. - case '|': - case '=': - case '!': - case '+': - case '-': - case '^': - case '*': - // '/' handled above. - case '%': - case ':': - case ';': - case ',': - case '(': case ')': - case '{': case '}': - case '[': case ']': - { - this->add_semi_at_eol_ = false; - Operator op = this->two_character_operator(cc, p[1]); - int chars; - if (op != OPERATOR_INVALID) - { - ++p; - chars = 2; - } - else - { - op = this->one_character_operator(cc); - chars = 1; - } - this->lineoff_ = p + 1 - this->linebuf_; - return this->make_operator(op, chars); - } - - case '.': - if (p[1] >= '0' && p[1] <= '9') - { - this->add_semi_at_eol_ = true; - this->lineoff_ = p - this->linebuf_; - return this->gather_number(); - } - if (p[1] == '.' && p[2] == '.') - { - this->add_semi_at_eol_ = false; - this->lineoff_ = p + 3 - this->linebuf_; - return this->make_operator(OPERATOR_ELLIPSIS, 3); - } - this->add_semi_at_eol_ = false; - this->lineoff_ = p + 1 - this->linebuf_; - return this->make_operator(OPERATOR_DOT, 1); - - default: - { - unsigned int ci; - bool issued_error; - this->lineoff_ = p - this->linebuf_; - const char *pnext = this->advance_one_utf8_char(p, &ci, - &issued_error); - - // Ignore byte order mark at start of file. - if (ci == 0xfeff) - { - p = pnext; - break; - } - - if (Lex::is_unicode_letter(ci)) - return this->gather_identifier(); - - if (!issued_error) - error_at(this->location(), - "invalid character 0x%x in input file", - ci); - - p = pend; - - break; - } - } - } - - this->lineoff_ = p - this->linebuf_; - } -} - -// Fetch one UTF-8 character from a string. Set *VALUE to the value. -// Return the number of bytes read from the string. Returns 0 if the -// string does not point to a valid UTF-8 character. - -int -Lex::fetch_char(const char* p, unsigned int* value) -{ - unsigned char c = *p; - if (c <= 0x7f) - { - *value = c; - return 1; - } - else if ((c & 0xe0) == 0xc0 - && (p[1] & 0xc0) == 0x80) - { - *value = (((c & 0x1f) << 6) - + (p[1] & 0x3f)); - if (*value <= 0x7f) - { - *value = 0xfffd; - return 0; - } - return 2; - } - else if ((c & 0xf0) == 0xe0 - && (p[1] & 0xc0) == 0x80 - && (p[2] & 0xc0) == 0x80) - { - *value = (((c & 0xf) << 12) - + ((p[1] & 0x3f) << 6) - + (p[2] & 0x3f)); - if (*value <= 0x7ff) - { - *value = 0xfffd; - return 0; - } - return 3; - } - else if ((c & 0xf8) == 0xf0 - && (p[1] & 0xc0) == 0x80 - && (p[2] & 0xc0) == 0x80 - && (p[3] & 0xc0) == 0x80) - { - *value = (((c & 0x7) << 18) - + ((p[1] & 0x3f) << 12) - + ((p[2] & 0x3f) << 6) - + (p[3] & 0x3f)); - if (*value <= 0xffff) - { - *value = 0xfffd; - return 0; - } - return 4; - } - else - { - /* Invalid encoding. Return the Unicode replacement - character. */ - *value = 0xfffd; - return 0; - } -} - -// Advance one UTF-8 character. Return the pointer beyond the -// character. Set *VALUE to the value. Set *ISSUED_ERROR if an error -// was issued. - -const char* -Lex::advance_one_utf8_char(const char* p, unsigned int* value, - bool* issued_error) -{ - *issued_error = false; - - if (*p == '\0') - { - error_at(this->location(), "invalid NUL byte"); - *issued_error = true; - *value = 0; - return p + 1; - } - - int adv = Lex::fetch_char(p, value); - if (adv == 0) - { - error_at(this->location(), "invalid UTF-8 encoding"); - *issued_error = true; - return p + 1; - } - - // Warn about byte order mark, except at start of file. - if (*value == 0xfeff && (this->lineno_ != 1 || this->lineoff_ != 0)) - { - error_at(this->location(), "Unicode (UTF-8) BOM in middle of file"); - *issued_error = true; - } - - return p + adv; -} - -// Pick up an identifier. - -Token -Lex::gather_identifier() -{ - const char* pstart = this->linebuf_ + this->lineoff_; - const char* p = pstart; - const char* pend = this->linebuf_ + this->linesize_; - bool is_first = true; - bool is_exported = false; - bool has_non_ascii_char = false; - std::string buf; - while (p < pend) - { - unsigned char cc = *p; - if (cc <= 0x7f) - { - if ((cc < 'A' || cc > 'Z') - && (cc < 'a' || cc > 'z') - && cc != '_' - && (cc < '0' || cc > '9')) - break; - ++p; - if (is_first) - { - is_exported = cc >= 'A' && cc <= 'Z'; - is_first = false; - } - if (has_non_ascii_char) - buf.push_back(cc); - } - else - { - unsigned int ci; - bool issued_error; - this->lineoff_ = p - this->linebuf_; - const char* pnext = this->advance_one_utf8_char(p, &ci, - &issued_error); - bool is_invalid = false; - if (!Lex::is_unicode_letter(ci) && !Lex::is_unicode_digit(ci)) - { - // There is no valid place for a non-ASCII character - // other than an identifier, so we get better error - // handling behaviour if we swallow this character after - // giving an error. - if (!issued_error) - error_at(this->location(), - "invalid character 0x%x in identifier", - ci); - is_invalid = true; - } - if (is_first) - { - is_exported = Lex::is_unicode_uppercase(ci); - is_first = false; - } - if (!has_non_ascii_char) - { - buf.assign(pstart, p - pstart); - has_non_ascii_char = true; - } - if (is_invalid && !Lex::is_invalid_identifier(buf)) - buf.append("$INVALID$"); - buf.append(p, pnext - p); - p = pnext; - } - } - Location location = this->location(); - this->add_semi_at_eol_ = true; - this->lineoff_ = p - this->linebuf_; - if (has_non_ascii_char) - return Token::make_identifier_token(buf, is_exported, location); - else - { - Keyword code = keywords.keyword_to_code(pstart, p - pstart); - if (code == KEYWORD_INVALID) - return Token::make_identifier_token(std::string(pstart, p - pstart), - is_exported, location); - else - { - switch (code) - { - case KEYWORD_BREAK: - case KEYWORD_CONTINUE: - case KEYWORD_FALLTHROUGH: - case KEYWORD_RETURN: - break; - default: - this->add_semi_at_eol_ = false; - break; - } - return Token::make_keyword_token(code, location); - } - } -} - -// Return whether C is a hex digit. - -bool -Lex::is_hex_digit(char c) -{ - return ((c >= '0' && c <= '9') - || (c >= 'A' && c <= 'F') - || (c >= 'a' && c <= 'f')); -} - -// Return whether an exponent could start at P. - -bool -Lex::could_be_exponent(const char* p, const char* pend) -{ - if (*p != 'e' && *p != 'E') - return false; - ++p; - if (p >= pend) - return false; - if (*p == '+' || *p == '-') - { - ++p; - if (p >= pend) - return false; - } - return *p >= '0' && *p <= '9'; -} - -// Pick up a number. - -Token -Lex::gather_number() -{ - const char* pstart = this->linebuf_ + this->lineoff_; - const char* p = pstart; - const char* pend = this->linebuf_ + this->linesize_; - - Location location = this->location(); - - bool neg = false; - if (*p == '+') - ++p; - else if (*p == '-') - { - ++p; - neg = true; - } - - const char* pnum = p; - if (*p == '0') - { - int base; - if ((p[1] == 'x' || p[1] == 'X') - && Lex::is_hex_digit(p[2])) - { - base = 16; - p += 2; - pnum = p; - while (p < pend) - { - if (!Lex::is_hex_digit(*p)) - break; - ++p; - } - } - else - { - base = 8; - pnum = p; - while (p < pend) - { - if (*p < '0' || *p > '7') - break; - ++p; - } - } - - // A partial token that looks like an octal literal might actually be the - // beginning of a floating-point or imaginary literal. - if (base == 16 || (*p != '.' && *p != 'i' && !Lex::could_be_exponent(p, pend))) - { - std::string s(pnum, p - pnum); - mpz_t val; - int r = mpz_init_set_str(val, s.c_str(), base); - go_assert(r == 0); - - if (neg) - mpz_neg(val, val); - - this->lineoff_ = p - this->linebuf_; - Token ret = Token::make_integer_token(val, location); - mpz_clear(val); - return ret; - } - } - - while (p < pend) - { - if (*p < '0' || *p > '9') - break; - ++p; - } - - if (*p != '.' && *p != 'i' && !Lex::could_be_exponent(p, pend)) - { - std::string s(pnum, p - pnum); - mpz_t val; - int r = mpz_init_set_str(val, s.c_str(), 10); - go_assert(r == 0); - - if (neg) - mpz_neg(val, val); - - this->lineoff_ = p - this->linebuf_; - Token ret = Token::make_integer_token(val, location); - mpz_clear(val); - return ret; - } - - if (*p != 'i') - { - bool dot = *p == '.'; - - ++p; - - if (!dot) - { - if (*p == '+' || *p == '-') - ++p; - } - - while (p < pend) - { - if (*p < '0' || *p > '9') - break; - ++p; - } - - if (dot && Lex::could_be_exponent(p, pend)) - { - ++p; - if (*p == '+' || *p == '-') - ++p; - while (p < pend) - { - if (*p < '0' || *p > '9') - break; - ++p; - } - } - } - - std::string s(pnum, p - pnum); - mpfr_t val; - int r = mpfr_init_set_str(val, s.c_str(), 10, GMP_RNDN); - go_assert(r == 0); - - if (neg) - mpfr_neg(val, val, GMP_RNDN); - - bool is_imaginary = *p == 'i'; - if (is_imaginary) - ++p; - - this->lineoff_ = p - this->linebuf_; - if (is_imaginary) - { - Token ret = Token::make_imaginary_token(val, location); - mpfr_clear(val); - return ret; - } - else - { - Token ret = Token::make_float_token(val, location); - mpfr_clear(val); - return ret; - } -} - -// Advance one character, possibly escaped. Return the pointer beyond -// the character. Set *VALUE to the character. Set *IS_CHARACTER if -// this is a character (e.g., 'a' or '\u1234') rather than a byte -// value (e.g., '\001'). - -const char* -Lex::advance_one_char(const char* p, bool is_single_quote, unsigned int* value, - bool* is_character) -{ - *value = 0; - *is_character = true; - if (*p != '\\') - { - bool issued_error; - const char* ret = this->advance_one_utf8_char(p, value, &issued_error); - if (is_single_quote - && (*value == '\'' || *value == '\n') - && !issued_error) - error_at(this->location(), "invalid character literal"); - return ret; - } - else - { - ++p; - switch (*p) - { - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - *is_character = false; - if (p[1] >= '0' && p[1] <= '7' - && p[2] >= '0' && p[2] <= '7') - { - *value = ((Lex::octal_value(p[0]) << 6) - + (Lex::octal_value(p[1]) << 3) - + Lex::octal_value(p[2])); - if (*value > 255) - { - error_at(this->location(), "invalid octal constant"); - *value = 255; - } - return p + 3; - } - error_at(this->location(), "invalid octal character"); - return (p[1] >= '0' && p[1] <= '7' - ? p + 2 - : p + 1); - - case 'x': - case 'X': - *is_character = false; - if (Lex::is_hex_digit(p[1]) && Lex::is_hex_digit(p[2])) - { - *value = (hex_value(p[1]) << 4) + hex_value(p[2]); - return p + 3; - } - error_at(this->location(), "invalid hex character"); - return (Lex::is_hex_digit(p[1]) - ? p + 2 - : p + 1); - - case 'a': - *value = '\a'; - return p + 1; - case 'b': - *value = '\b'; - return p + 1; - case 'f': - *value = '\f'; - return p + 1; - case 'n': - *value = '\n'; - return p + 1; - case 'r': - *value = '\r'; - return p + 1; - case 't': - *value = '\t'; - return p + 1; - case 'v': - *value = '\v'; - return p + 1; - case '\\': - *value = '\\'; - return p + 1; - case '\'': - if (!is_single_quote) - error_at(this->location(), "invalid quoted character"); - *value = '\''; - return p + 1; - case '"': - if (is_single_quote) - error_at(this->location(), "invalid quoted character"); - *value = '"'; - return p + 1; - - case 'u': - if (Lex::is_hex_digit(p[1]) && Lex::is_hex_digit(p[2]) - && Lex::is_hex_digit(p[3]) && Lex::is_hex_digit(p[4])) - { - *value = ((hex_value(p[1]) << 12) - + (hex_value(p[2]) << 8) - + (hex_value(p[3]) << 4) - + hex_value(p[4])); - if (*value >= 0xd800 && *value < 0xe000) - { - error_at(this->location(), - "invalid unicode code point 0x%x", - *value); - // Use the replacement character. - *value = 0xfffd; - } - return p + 5; - } - error_at(this->location(), "invalid little unicode code point"); - return p + 1; - - case 'U': - if (Lex::is_hex_digit(p[1]) && Lex::is_hex_digit(p[2]) - && Lex::is_hex_digit(p[3]) && Lex::is_hex_digit(p[4]) - && Lex::is_hex_digit(p[5]) && Lex::is_hex_digit(p[6]) - && Lex::is_hex_digit(p[7]) && Lex::is_hex_digit(p[8])) - { - *value = ((hex_value(p[1]) << 28) - + (hex_value(p[2]) << 24) - + (hex_value(p[3]) << 20) - + (hex_value(p[4]) << 16) - + (hex_value(p[5]) << 12) - + (hex_value(p[6]) << 8) - + (hex_value(p[7]) << 4) - + hex_value(p[8])); - if (*value > 0x10ffff - || (*value >= 0xd800 && *value < 0xe000)) - { - error_at(this->location(), "invalid unicode code point 0x%x", - *value); - // Use the replacement character. - *value = 0xfffd; - } - return p + 9; - } - error_at(this->location(), "invalid big unicode code point"); - return p + 1; - - default: - error_at(this->location(), "invalid character after %<\\%>"); - *value = *p; - return p + 1; - } - } -} - -// Append V to STR. IS_CHARACTER is true for a character which should -// be stored in UTF-8, false for a general byte value which should be -// stored directly. - -void -Lex::append_char(unsigned int v, bool is_character, std::string* str, - Location location) -{ - char buf[4]; - size_t len; - if (v <= 0x7f || !is_character) - { - buf[0] = v; - len = 1; - } - else if (v <= 0x7ff) - { - buf[0] = 0xc0 + (v >> 6); - buf[1] = 0x80 + (v & 0x3f); - len = 2; - } - else - { - if (v > 0x10ffff) - { - warning_at(location, 0, - "unicode code point 0x%x out of range in string", v); - // Turn it into the "replacement character". - v = 0xfffd; - } - if (v >= 0xd800 && v < 0xe000) - { - warning_at(location, 0, - "unicode code point 0x%x is invalid surrogate pair", v); - v = 0xfffd; - } - if (v <= 0xffff) - { - buf[0] = 0xe0 + (v >> 12); - buf[1] = 0x80 + ((v >> 6) & 0x3f); - buf[2] = 0x80 + (v & 0x3f); - len = 3; - } - else - { - buf[0] = 0xf0 + (v >> 18); - buf[1] = 0x80 + ((v >> 12) & 0x3f); - buf[2] = 0x80 + ((v >> 6) & 0x3f); - buf[3] = 0x80 + (v & 0x3f); - len = 4; - } - } - str->append(buf, len); -} - -// Pick up a character literal. - -Token -Lex::gather_character() -{ - ++this->lineoff_; - const char* pstart = this->linebuf_ + this->lineoff_; - const char* p = pstart; - - unsigned int value; - bool is_character; - p = this->advance_one_char(p, true, &value, &is_character); - - if (*p != '\'') - { - error_at(this->location(), "unterminated character constant"); - this->lineoff_ = p - this->linebuf_; - return this->make_invalid_token(); - } - - mpz_t val; - mpz_init_set_ui(val, value); - - Location location = this->location(); - this->lineoff_ = p + 1 - this->linebuf_; - Token ret = Token::make_character_token(val, location); - mpz_clear(val); - return ret; -} - -// Pick up a quoted string. - -Token -Lex::gather_string() -{ - const char* pstart = this->linebuf_ + this->lineoff_ + 1; - const char* p = pstart; - const char* pend = this->linebuf_ + this->linesize_; - - std::string value; - while (*p != '"') - { - Location loc = this->location(); - unsigned int c; - bool is_character; - this->lineoff_ = p - this->linebuf_; - p = this->advance_one_char(p, false, &c, &is_character); - if (p >= pend) - { - error_at(this->location(), "unterminated string"); - --p; - break; - } - Lex::append_char(c, is_character, &value, loc); - } - - Location location = this->location(); - this->lineoff_ = p + 1 - this->linebuf_; - return Token::make_string_token(value, location); -} - -// Pick up a raw string. - -Token -Lex::gather_raw_string() -{ - const char* p = this->linebuf_ + this->lineoff_ + 1; - const char* pend = this->linebuf_ + this->linesize_; - Location location = this->location(); - - std::string value; - while (true) - { - while (p < pend) - { - if (*p == '`') - { - this->lineoff_ = p + 1 - this->linebuf_; - return Token::make_string_token(value, location); - } - Location loc = this->location(); - unsigned int c; - bool issued_error; - this->lineoff_ = p - this->linebuf_; - p = this->advance_one_utf8_char(p, &c, &issued_error); - Lex::append_char(c, true, &value, loc); - } - this->lineoff_ = p - this->linebuf_; - if (!this->require_line()) - { - error_at(location, "unterminated raw string"); - return Token::make_string_token(value, location); - } - p = this->linebuf_ + this->lineoff_; - pend = this->linebuf_ + this->linesize_; - } -} - -// If C1 C2 C3 are a three character operator, return the code. - -Operator -Lex::three_character_operator(char c1, char c2, char c3) -{ - if (c3 == '=') - { - if (c1 == '<' && c2 == '<') - return OPERATOR_LSHIFTEQ; - else if (c1 == '>' && c2 == '>') - return OPERATOR_RSHIFTEQ; - else if (c1 == '&' && c2 == '^') - return OPERATOR_BITCLEAREQ; - } - return OPERATOR_INVALID; -} - -// If C1 C2 are a two character operator, return the code. - -Operator -Lex::two_character_operator(char c1, char c2) -{ - switch (c1) - { - case '|': - if (c2 == '|') - return OPERATOR_OROR; - else if (c2 == '=') - return OPERATOR_OREQ; - break; - case '&': - if (c2 == '&') - return OPERATOR_ANDAND; - else if (c2 == '^') - return OPERATOR_BITCLEAR; - else if (c2 == '=') - return OPERATOR_ANDEQ; - break; - case '^': - if (c2 == '=') - return OPERATOR_XOREQ; - break; - case '=': - if (c2 == '=') - return OPERATOR_EQEQ; - break; - case '!': - if (c2 == '=') - return OPERATOR_NOTEQ; - break; - case '<': - if (c2 == '=') - return OPERATOR_LE; - else if (c2 == '<') - return OPERATOR_LSHIFT; - else if (c2 == '-') - return OPERATOR_CHANOP; - break; - case '>': - if (c2 == '=') - return OPERATOR_GE; - else if (c2 == '>') - return OPERATOR_RSHIFT; - break; - case '*': - if (c2 == '=') - return OPERATOR_MULTEQ; - break; - case '/': - if (c2 == '=') - return OPERATOR_DIVEQ; - break; - case '%': - if (c2 == '=') - return OPERATOR_MODEQ; - break; - case '+': - if (c2 == '+') - { - this->add_semi_at_eol_ = true; - return OPERATOR_PLUSPLUS; - } - else if (c2 == '=') - return OPERATOR_PLUSEQ; - break; - case '-': - if (c2 == '-') - { - this->add_semi_at_eol_ = true; - return OPERATOR_MINUSMINUS; - } - else if (c2 == '=') - return OPERATOR_MINUSEQ; - break; - case ':': - if (c2 == '=') - return OPERATOR_COLONEQ; - break; - default: - break; - } - return OPERATOR_INVALID; -} - -// If character C is an operator, return the code. - -Operator -Lex::one_character_operator(char c) -{ - switch (c) - { - case '<': - return OPERATOR_LT; - case '>': - return OPERATOR_GT; - case '+': - return OPERATOR_PLUS; - case '-': - return OPERATOR_MINUS; - case '|': - return OPERATOR_OR; - case '^': - return OPERATOR_XOR; - case '*': - return OPERATOR_MULT; - case '/': - return OPERATOR_DIV; - case '%': - return OPERATOR_MOD; - case '&': - return OPERATOR_AND; - case '!': - return OPERATOR_NOT; - case '=': - return OPERATOR_EQ; - case ':': - return OPERATOR_COLON; - case ';': - return OPERATOR_SEMICOLON; - case '.': - return OPERATOR_DOT; - case ',': - return OPERATOR_COMMA; - case '(': - return OPERATOR_LPAREN; - case ')': - this->add_semi_at_eol_ = true; - return OPERATOR_RPAREN; - case '{': - return OPERATOR_LCURLY; - case '}': - this->add_semi_at_eol_ = true; - return OPERATOR_RCURLY; - case '[': - return OPERATOR_LSQUARE; - case ']': - this->add_semi_at_eol_ = true; - return OPERATOR_RSQUARE; - default: - return OPERATOR_INVALID; - } -} - -// Skip a C-style comment. - -bool -Lex::skip_c_comment() -{ - while (true) - { - if (!this->require_line()) - { - error_at(this->location(), "unterminated comment"); - return false; - } - - const char* p = this->linebuf_ + this->lineoff_; - const char* pend = this->linebuf_ + this->linesize_; - - while (p < pend) - { - if (p[0] == '*' && p + 1 < pend && p[1] == '/') - { - this->lineoff_ = p + 2 - this->linebuf_; - return true; - } - - this->lineoff_ = p - this->linebuf_; - unsigned int c; - bool issued_error; - p = this->advance_one_utf8_char(p, &c, &issued_error); - } - - this->lineoff_ = p - this->linebuf_; - } -} - -// Skip a C++-style comment. - -void -Lex::skip_cpp_comment() -{ - // Ensure that if EXTERN_ is set, it means that we just saw a - // //extern comment. - this->extern_.clear(); - - const char* p = this->linebuf_ + this->lineoff_; - const char* pend = this->linebuf_ + this->linesize_; - - // By convention, a C++ comment at the start of the line of the form - // //line FILE:LINENO - // is interpreted as setting the file name and line number of the - // next source line. - - if (this->lineoff_ == 2 - && pend - p > 5 - && memcmp(p, "line ", 5) == 0) - { - p += 5; - while (p < pend && *p == ' ') - ++p; - const char* pcolon = static_cast<const char*>(memchr(p, ':', pend - p)); - if (pcolon != NULL - && pcolon[1] >= '0' - && pcolon[1] <= '9') - { - char* plend; - long lineno = strtol(pcolon + 1, &plend, 10); - if (plend > pcolon + 1 - && (plend == pend - || *plend < '0' - || *plend > '9') - && lineno > 0 - && lineno < 0x7fffffff) - { - unsigned int filelen = pcolon - p; - char* file = new char[filelen + 1]; - memcpy(file, p, filelen); - file[filelen] = '\0'; - - this->linemap_->start_file(file, lineno); - this->lineno_ = lineno - 1; - - p = plend; - } - } - } - - // As a special gccgo extension, a C++ comment at the start of the - // line of the form - // //extern NAME - // which immediately precedes a function declaration means that the - // external name of the function declaration is NAME. This is - // normally used to permit Go code to call a C function. - if (this->lineoff_ == 2 - && pend - p > 7 - && memcmp(p, "extern ", 7) == 0) - { - p += 7; - while (p < pend && (*p == ' ' || *p == '\t')) - ++p; - const char* plend = pend; - while (plend > p - && (plend[-1] == ' ' || plend[-1] == '\t' || plend[-1] == '\n')) - --plend; - if (plend > p) - this->extern_ = std::string(p, plend - p); - } - - // For field tracking analysis: a //go:nointerface comment means - // that the next interface method should not be stored in the type - // descriptor. This permits it to be discarded if it is not needed. - if (this->lineoff_ == 2 && memcmp(p, "go:nointerface", 14) == 0) - this->saw_nointerface_ = true; - - while (p < pend) - { - this->lineoff_ = p - this->linebuf_; - unsigned int c; - bool issued_error; - p = this->advance_one_utf8_char(p, &c, &issued_error); - if (issued_error) - this->extern_.clear(); - } -} - -// The Unicode tables use this struct. - -struct Unicode_range -{ - // The low end of the range. - unsigned int low; - // The high end of the range. - unsigned int high; - // The stride. This entries represents low, low + stride, low + 2 * - // stride, etc., up to high. - unsigned int stride; -}; - -// A table of whitespace characters--Unicode code points classified as -// "Space", "C" locale whitespace characters, the "next line" control -// character (0085), the line separator (2028), the paragraph -// separator (2029), and the "zero-width non-break space" (feff). - -static const Unicode_range unicode_space[] = -{ - { 0x0009, 0x000d, 1 }, - { 0x0020, 0x0020, 1 }, - { 0x0085, 0x0085, 1 }, - { 0x00a0, 0x00a0, 1 }, - { 0x1680, 0x1680, 1 }, - { 0x180e, 0x180e, 1 }, - { 0x2000, 0x200a, 1 }, - { 0x2028, 0x2029, 1 }, - { 0x202f, 0x202f, 1 }, - { 0x205f, 0x205f, 1 }, - { 0x3000, 0x3000, 1 }, - { 0xfeff, 0xfeff, 1 }, -}; - -// A table of Unicode digits--Unicode code points classified as -// "Digit". - -static const Unicode_range unicode_digits[] = -{ - { 0x0030, 0x0039, 1}, - { 0x0660, 0x0669, 1}, - { 0x06f0, 0x06f9, 1}, - { 0x07c0, 0x07c9, 1}, - { 0x0966, 0x096f, 1}, - { 0x09e6, 0x09ef, 1}, - { 0x0a66, 0x0a6f, 1}, - { 0x0ae6, 0x0aef, 1}, - { 0x0b66, 0x0b6f, 1}, - { 0x0be6, 0x0bef, 1}, - { 0x0c66, 0x0c6f, 1}, - { 0x0ce6, 0x0cef, 1}, - { 0x0d66, 0x0d6f, 1}, - { 0x0e50, 0x0e59, 1}, - { 0x0ed0, 0x0ed9, 1}, - { 0x0f20, 0x0f29, 1}, - { 0x1040, 0x1049, 1}, - { 0x17e0, 0x17e9, 1}, - { 0x1810, 0x1819, 1}, - { 0x1946, 0x194f, 1}, - { 0x19d0, 0x19d9, 1}, - { 0x1b50, 0x1b59, 1}, - { 0xff10, 0xff19, 1}, - { 0x104a0, 0x104a9, 1}, - { 0x1d7ce, 0x1d7ff, 1}, -}; - -// A table of Unicode letters--Unicode code points classified as -// "Letter". - -static const Unicode_range unicode_letters[] = -{ - { 0x0041, 0x005a, 1}, - { 0x0061, 0x007a, 1}, - { 0x00aa, 0x00b5, 11}, - { 0x00ba, 0x00ba, 1}, - { 0x00c0, 0x00d6, 1}, - { 0x00d8, 0x00f6, 1}, - { 0x00f8, 0x02c1, 1}, - { 0x02c6, 0x02d1, 1}, - { 0x02e0, 0x02e4, 1}, - { 0x02ec, 0x02ee, 2}, - { 0x0370, 0x0374, 1}, - { 0x0376, 0x0377, 1}, - { 0x037a, 0x037d, 1}, - { 0x0386, 0x0386, 1}, - { 0x0388, 0x038a, 1}, - { 0x038c, 0x038c, 1}, - { 0x038e, 0x03a1, 1}, - { 0x03a3, 0x03f5, 1}, - { 0x03f7, 0x0481, 1}, - { 0x048a, 0x0523, 1}, - { 0x0531, 0x0556, 1}, - { 0x0559, 0x0559, 1}, - { 0x0561, 0x0587, 1}, - { 0x05d0, 0x05ea, 1}, - { 0x05f0, 0x05f2, 1}, - { 0x0621, 0x064a, 1}, - { 0x066e, 0x066f, 1}, - { 0x0671, 0x06d3, 1}, - { 0x06d5, 0x06d5, 1}, - { 0x06e5, 0x06e6, 1}, - { 0x06ee, 0x06ef, 1}, - { 0x06fa, 0x06fc, 1}, - { 0x06ff, 0x0710, 17}, - { 0x0712, 0x072f, 1}, - { 0x074d, 0x07a5, 1}, - { 0x07b1, 0x07b1, 1}, - { 0x07ca, 0x07ea, 1}, - { 0x07f4, 0x07f5, 1}, - { 0x07fa, 0x07fa, 1}, - { 0x0904, 0x0939, 1}, - { 0x093d, 0x0950, 19}, - { 0x0958, 0x0961, 1}, - { 0x0971, 0x0972, 1}, - { 0x097b, 0x097f, 1}, - { 0x0985, 0x098c, 1}, - { 0x098f, 0x0990, 1}, - { 0x0993, 0x09a8, 1}, - { 0x09aa, 0x09b0, 1}, - { 0x09b2, 0x09b2, 1}, - { 0x09b6, 0x09b9, 1}, - { 0x09bd, 0x09ce, 17}, - { 0x09dc, 0x09dd, 1}, - { 0x09df, 0x09e1, 1}, - { 0x09f0, 0x09f1, 1}, - { 0x0a05, 0x0a0a, 1}, - { 0x0a0f, 0x0a10, 1}, - { 0x0a13, 0x0a28, 1}, - { 0x0a2a, 0x0a30, 1}, - { 0x0a32, 0x0a33, 1}, - { 0x0a35, 0x0a36, 1}, - { 0x0a38, 0x0a39, 1}, - { 0x0a59, 0x0a5c, 1}, - { 0x0a5e, 0x0a5e, 1}, - { 0x0a72, 0x0a74, 1}, - { 0x0a85, 0x0a8d, 1}, - { 0x0a8f, 0x0a91, 1}, - { 0x0a93, 0x0aa8, 1}, - { 0x0aaa, 0x0ab0, 1}, - { 0x0ab2, 0x0ab3, 1}, - { 0x0ab5, 0x0ab9, 1}, - { 0x0abd, 0x0ad0, 19}, - { 0x0ae0, 0x0ae1, 1}, - { 0x0b05, 0x0b0c, 1}, - { 0x0b0f, 0x0b10, 1}, - { 0x0b13, 0x0b28, 1}, - { 0x0b2a, 0x0b30, 1}, - { 0x0b32, 0x0b33, 1}, - { 0x0b35, 0x0b39, 1}, - { 0x0b3d, 0x0b3d, 1}, - { 0x0b5c, 0x0b5d, 1}, - { 0x0b5f, 0x0b61, 1}, - { 0x0b71, 0x0b83, 18}, - { 0x0b85, 0x0b8a, 1}, - { 0x0b8e, 0x0b90, 1}, - { 0x0b92, 0x0b95, 1}, - { 0x0b99, 0x0b9a, 1}, - { 0x0b9c, 0x0b9c, 1}, - { 0x0b9e, 0x0b9f, 1}, - { 0x0ba3, 0x0ba4, 1}, - { 0x0ba8, 0x0baa, 1}, - { 0x0bae, 0x0bb9, 1}, - { 0x0bd0, 0x0bd0, 1}, - { 0x0c05, 0x0c0c, 1}, - { 0x0c0e, 0x0c10, 1}, - { 0x0c12, 0x0c28, 1}, - { 0x0c2a, 0x0c33, 1}, - { 0x0c35, 0x0c39, 1}, - { 0x0c3d, 0x0c3d, 1}, - { 0x0c58, 0x0c59, 1}, - { 0x0c60, 0x0c61, 1}, - { 0x0c85, 0x0c8c, 1}, - { 0x0c8e, 0x0c90, 1}, - { 0x0c92, 0x0ca8, 1}, - { 0x0caa, 0x0cb3, 1}, - { 0x0cb5, 0x0cb9, 1}, - { 0x0cbd, 0x0cde, 33}, - { 0x0ce0, 0x0ce1, 1}, - { 0x0d05, 0x0d0c, 1}, - { 0x0d0e, 0x0d10, 1}, - { 0x0d12, 0x0d28, 1}, - { 0x0d2a, 0x0d39, 1}, - { 0x0d3d, 0x0d3d, 1}, - { 0x0d60, 0x0d61, 1}, - { 0x0d7a, 0x0d7f, 1}, - { 0x0d85, 0x0d96, 1}, - { 0x0d9a, 0x0db1, 1}, - { 0x0db3, 0x0dbb, 1}, - { 0x0dbd, 0x0dbd, 1}, - { 0x0dc0, 0x0dc6, 1}, - { 0x0e01, 0x0e30, 1}, - { 0x0e32, 0x0e33, 1}, - { 0x0e40, 0x0e46, 1}, - { 0x0e81, 0x0e82, 1}, - { 0x0e84, 0x0e84, 1}, - { 0x0e87, 0x0e88, 1}, - { 0x0e8a, 0x0e8d, 3}, - { 0x0e94, 0x0e97, 1}, - { 0x0e99, 0x0e9f, 1}, - { 0x0ea1, 0x0ea3, 1}, - { 0x0ea5, 0x0ea7, 2}, - { 0x0eaa, 0x0eab, 1}, - { 0x0ead, 0x0eb0, 1}, - { 0x0eb2, 0x0eb3, 1}, - { 0x0ebd, 0x0ebd, 1}, - { 0x0ec0, 0x0ec4, 1}, - { 0x0ec6, 0x0ec6, 1}, - { 0x0edc, 0x0edd, 1}, - { 0x0f00, 0x0f00, 1}, - { 0x0f40, 0x0f47, 1}, - { 0x0f49, 0x0f6c, 1}, - { 0x0f88, 0x0f8b, 1}, - { 0x1000, 0x102a, 1}, - { 0x103f, 0x103f, 1}, - { 0x1050, 0x1055, 1}, - { 0x105a, 0x105d, 1}, - { 0x1061, 0x1061, 1}, - { 0x1065, 0x1066, 1}, - { 0x106e, 0x1070, 1}, - { 0x1075, 0x1081, 1}, - { 0x108e, 0x108e, 1}, - { 0x10a0, 0x10c5, 1}, - { 0x10d0, 0x10fa, 1}, - { 0x10fc, 0x10fc, 1}, - { 0x1100, 0x1159, 1}, - { 0x115f, 0x11a2, 1}, - { 0x11a8, 0x11f9, 1}, - { 0x1200, 0x1248, 1}, - { 0x124a, 0x124d, 1}, - { 0x1250, 0x1256, 1}, - { 0x1258, 0x1258, 1}, - { 0x125a, 0x125d, 1}, - { 0x1260, 0x1288, 1}, - { 0x128a, 0x128d, 1}, - { 0x1290, 0x12b0, 1}, - { 0x12b2, 0x12b5, 1}, - { 0x12b8, 0x12be, 1}, - { 0x12c0, 0x12c0, 1}, - { 0x12c2, 0x12c5, 1}, - { 0x12c8, 0x12d6, 1}, - { 0x12d8, 0x1310, 1}, - { 0x1312, 0x1315, 1}, - { 0x1318, 0x135a, 1}, - { 0x1380, 0x138f, 1}, - { 0x13a0, 0x13f4, 1}, - { 0x1401, 0x166c, 1}, - { 0x166f, 0x1676, 1}, - { 0x1681, 0x169a, 1}, - { 0x16a0, 0x16ea, 1}, - { 0x1700, 0x170c, 1}, - { 0x170e, 0x1711, 1}, - { 0x1720, 0x1731, 1}, - { 0x1740, 0x1751, 1}, - { 0x1760, 0x176c, 1}, - { 0x176e, 0x1770, 1}, - { 0x1780, 0x17b3, 1}, - { 0x17d7, 0x17dc, 5}, - { 0x1820, 0x1877, 1}, - { 0x1880, 0x18a8, 1}, - { 0x18aa, 0x18aa, 1}, - { 0x1900, 0x191c, 1}, - { 0x1950, 0x196d, 1}, - { 0x1970, 0x1974, 1}, - { 0x1980, 0x19a9, 1}, - { 0x19c1, 0x19c7, 1}, - { 0x1a00, 0x1a16, 1}, - { 0x1b05, 0x1b33, 1}, - { 0x1b45, 0x1b4b, 1}, - { 0x1b83, 0x1ba0, 1}, - { 0x1bae, 0x1baf, 1}, - { 0x1c00, 0x1c23, 1}, - { 0x1c4d, 0x1c4f, 1}, - { 0x1c5a, 0x1c7d, 1}, - { 0x1d00, 0x1dbf, 1}, - { 0x1e00, 0x1f15, 1}, - { 0x1f18, 0x1f1d, 1}, - { 0x1f20, 0x1f45, 1}, - { 0x1f48, 0x1f4d, 1}, - { 0x1f50, 0x1f57, 1}, - { 0x1f59, 0x1f5d, 2}, - { 0x1f5f, 0x1f7d, 1}, - { 0x1f80, 0x1fb4, 1}, - { 0x1fb6, 0x1fbc, 1}, - { 0x1fbe, 0x1fbe, 1}, - { 0x1fc2, 0x1fc4, 1}, - { 0x1fc6, 0x1fcc, 1}, - { 0x1fd0, 0x1fd3, 1}, - { 0x1fd6, 0x1fdb, 1}, - { 0x1fe0, 0x1fec, 1}, - { 0x1ff2, 0x1ff4, 1}, - { 0x1ff6, 0x1ffc, 1}, - { 0x2071, 0x207f, 14}, - { 0x2090, 0x2094, 1}, - { 0x2102, 0x2107, 5}, - { 0x210a, 0x2113, 1}, - { 0x2115, 0x2115, 1}, - { 0x2119, 0x211d, 1}, - { 0x2124, 0x2128, 2}, - { 0x212a, 0x212d, 1}, - { 0x212f, 0x2139, 1}, - { 0x213c, 0x213f, 1}, - { 0x2145, 0x2149, 1}, - { 0x214e, 0x214e, 1}, - { 0x2183, 0x2184, 1}, - { 0x2c00, 0x2c2e, 1}, - { 0x2c30, 0x2c5e, 1}, - { 0x2c60, 0x2c6f, 1}, - { 0x2c71, 0x2c7d, 1}, - { 0x2c80, 0x2ce4, 1}, - { 0x2d00, 0x2d25, 1}, - { 0x2d30, 0x2d65, 1}, - { 0x2d6f, 0x2d6f, 1}, - { 0x2d80, 0x2d96, 1}, - { 0x2da0, 0x2da6, 1}, - { 0x2da8, 0x2dae, 1}, - { 0x2db0, 0x2db6, 1}, - { 0x2db8, 0x2dbe, 1}, - { 0x2dc0, 0x2dc6, 1}, - { 0x2dc8, 0x2dce, 1}, - { 0x2dd0, 0x2dd6, 1}, - { 0x2dd8, 0x2dde, 1}, - { 0x2e2f, 0x2e2f, 1}, - { 0x3005, 0x3006, 1}, - { 0x3031, 0x3035, 1}, - { 0x303b, 0x303c, 1}, - { 0x3041, 0x3096, 1}, - { 0x309d, 0x309f, 1}, - { 0x30a1, 0x30fa, 1}, - { 0x30fc, 0x30ff, 1}, - { 0x3105, 0x312d, 1}, - { 0x3131, 0x318e, 1}, - { 0x31a0, 0x31b7, 1}, - { 0x31f0, 0x31ff, 1}, - { 0x3400, 0x4db5, 1}, - { 0x4e00, 0x9fc3, 1}, - { 0xa000, 0xa48c, 1}, - { 0xa500, 0xa60c, 1}, - { 0xa610, 0xa61f, 1}, - { 0xa62a, 0xa62b, 1}, - { 0xa640, 0xa65f, 1}, - { 0xa662, 0xa66e, 1}, - { 0xa67f, 0xa697, 1}, - { 0xa717, 0xa71f, 1}, - { 0xa722, 0xa788, 1}, - { 0xa78b, 0xa78c, 1}, - { 0xa7fb, 0xa801, 1}, - { 0xa803, 0xa805, 1}, - { 0xa807, 0xa80a, 1}, - { 0xa80c, 0xa822, 1}, - { 0xa840, 0xa873, 1}, - { 0xa882, 0xa8b3, 1}, - { 0xa90a, 0xa925, 1}, - { 0xa930, 0xa946, 1}, - { 0xaa00, 0xaa28, 1}, - { 0xaa40, 0xaa42, 1}, - { 0xaa44, 0xaa4b, 1}, - { 0xac00, 0xd7a3, 1}, - { 0xf900, 0xfa2d, 1}, - { 0xfa30, 0xfa6a, 1}, - { 0xfa70, 0xfad9, 1}, - { 0xfb00, 0xfb06, 1}, - { 0xfb13, 0xfb17, 1}, - { 0xfb1d, 0xfb1d, 1}, - { 0xfb1f, 0xfb28, 1}, - { 0xfb2a, 0xfb36, 1}, - { 0xfb38, 0xfb3c, 1}, - { 0xfb3e, 0xfb3e, 1}, - { 0xfb40, 0xfb41, 1}, - { 0xfb43, 0xfb44, 1}, - { 0xfb46, 0xfbb1, 1}, - { 0xfbd3, 0xfd3d, 1}, - { 0xfd50, 0xfd8f, 1}, - { 0xfd92, 0xfdc7, 1}, - { 0xfdf0, 0xfdfb, 1}, - { 0xfe70, 0xfe74, 1}, - { 0xfe76, 0xfefc, 1}, - { 0xff21, 0xff3a, 1}, - { 0xff41, 0xff5a, 1}, - { 0xff66, 0xffbe, 1}, - { 0xffc2, 0xffc7, 1}, - { 0xffca, 0xffcf, 1}, - { 0xffd2, 0xffd7, 1}, - { 0xffda, 0xffdc, 1}, - { 0x10000, 0x1000b, 1}, - { 0x1000d, 0x10026, 1}, - { 0x10028, 0x1003a, 1}, - { 0x1003c, 0x1003d, 1}, - { 0x1003f, 0x1004d, 1}, - { 0x10050, 0x1005d, 1}, - { 0x10080, 0x100fa, 1}, - { 0x10280, 0x1029c, 1}, - { 0x102a0, 0x102d0, 1}, - { 0x10300, 0x1031e, 1}, - { 0x10330, 0x10340, 1}, - { 0x10342, 0x10349, 1}, - { 0x10380, 0x1039d, 1}, - { 0x103a0, 0x103c3, 1}, - { 0x103c8, 0x103cf, 1}, - { 0x10400, 0x1049d, 1}, - { 0x10800, 0x10805, 1}, - { 0x10808, 0x10808, 1}, - { 0x1080a, 0x10835, 1}, - { 0x10837, 0x10838, 1}, - { 0x1083c, 0x1083f, 3}, - { 0x10900, 0x10915, 1}, - { 0x10920, 0x10939, 1}, - { 0x10a00, 0x10a00, 1}, - { 0x10a10, 0x10a13, 1}, - { 0x10a15, 0x10a17, 1}, - { 0x10a19, 0x10a33, 1}, - { 0x12000, 0x1236e, 1}, - { 0x1d400, 0x1d454, 1}, - { 0x1d456, 0x1d49c, 1}, - { 0x1d49e, 0x1d49f, 1}, - { 0x1d4a2, 0x1d4a2, 1}, - { 0x1d4a5, 0x1d4a6, 1}, - { 0x1d4a9, 0x1d4ac, 1}, - { 0x1d4ae, 0x1d4b9, 1}, - { 0x1d4bb, 0x1d4bb, 1}, - { 0x1d4bd, 0x1d4c3, 1}, - { 0x1d4c5, 0x1d505, 1}, - { 0x1d507, 0x1d50a, 1}, - { 0x1d50d, 0x1d514, 1}, - { 0x1d516, 0x1d51c, 1}, - { 0x1d51e, 0x1d539, 1}, - { 0x1d53b, 0x1d53e, 1}, - { 0x1d540, 0x1d544, 1}, - { 0x1d546, 0x1d546, 1}, - { 0x1d54a, 0x1d550, 1}, - { 0x1d552, 0x1d6a5, 1}, - { 0x1d6a8, 0x1d6c0, 1}, - { 0x1d6c2, 0x1d6da, 1}, - { 0x1d6dc, 0x1d6fa, 1}, - { 0x1d6fc, 0x1d714, 1}, - { 0x1d716, 0x1d734, 1}, - { 0x1d736, 0x1d74e, 1}, - { 0x1d750, 0x1d76e, 1}, - { 0x1d770, 0x1d788, 1}, - { 0x1d78a, 0x1d7a8, 1}, - { 0x1d7aa, 0x1d7c2, 1}, - { 0x1d7c4, 0x1d7cb, 1}, - { 0x20000, 0x2a6d6, 1}, - { 0x2f800, 0x2fa1d, 1}, -}; - -// A table of Unicode uppercase letters--Unicode code points -// classified as "Letter, uppercase". - -static const Unicode_range unicode_uppercase_letters[] = -{ - { 0x0041, 0x005a, 1}, - { 0x00c0, 0x00d6, 1}, - { 0x00d8, 0x00de, 1}, - { 0x0100, 0x0136, 2}, - { 0x0139, 0x0147, 2}, - { 0x014a, 0x0176, 2}, - { 0x0178, 0x0179, 1}, - { 0x017b, 0x017d, 2}, - { 0x0181, 0x0182, 1}, - { 0x0184, 0x0184, 1}, - { 0x0186, 0x0187, 1}, - { 0x0189, 0x018b, 1}, - { 0x018e, 0x0191, 1}, - { 0x0193, 0x0194, 1}, - { 0x0196, 0x0198, 1}, - { 0x019c, 0x019d, 1}, - { 0x019f, 0x01a0, 1}, - { 0x01a2, 0x01a4, 2}, - { 0x01a6, 0x01a7, 1}, - { 0x01a9, 0x01ac, 3}, - { 0x01ae, 0x01af, 1}, - { 0x01b1, 0x01b3, 1}, - { 0x01b5, 0x01b5, 1}, - { 0x01b7, 0x01b8, 1}, - { 0x01bc, 0x01c4, 8}, - { 0x01c7, 0x01cd, 3}, - { 0x01cf, 0x01db, 2}, - { 0x01de, 0x01ee, 2}, - { 0x01f1, 0x01f4, 3}, - { 0x01f6, 0x01f8, 1}, - { 0x01fa, 0x0232, 2}, - { 0x023a, 0x023b, 1}, - { 0x023d, 0x023e, 1}, - { 0x0241, 0x0241, 1}, - { 0x0243, 0x0246, 1}, - { 0x0248, 0x024e, 2}, - { 0x0370, 0x0372, 2}, - { 0x0376, 0x0386, 16}, - { 0x0388, 0x038a, 1}, - { 0x038c, 0x038c, 1}, - { 0x038e, 0x038f, 1}, - { 0x0391, 0x03a1, 1}, - { 0x03a3, 0x03ab, 1}, - { 0x03cf, 0x03cf, 1}, - { 0x03d2, 0x03d4, 1}, - { 0x03d8, 0x03ee, 2}, - { 0x03f4, 0x03f7, 3}, - { 0x03f9, 0x03fa, 1}, - { 0x03fd, 0x042f, 1}, - { 0x0460, 0x0480, 2}, - { 0x048a, 0x04be, 2}, - { 0x04c0, 0x04c1, 1}, - { 0x04c3, 0x04cd, 2}, - { 0x04d0, 0x0522, 2}, - { 0x0531, 0x0556, 1}, - { 0x10a0, 0x10c5, 1}, - { 0x1e00, 0x1e94, 2}, - { 0x1e9e, 0x1efe, 2}, - { 0x1f08, 0x1f0f, 1}, - { 0x1f18, 0x1f1d, 1}, - { 0x1f28, 0x1f2f, 1}, - { 0x1f38, 0x1f3f, 1}, - { 0x1f48, 0x1f4d, 1}, - { 0x1f59, 0x1f5f, 2}, - { 0x1f68, 0x1f6f, 1}, - { 0x1fb8, 0x1fbb, 1}, - { 0x1fc8, 0x1fcb, 1}, - { 0x1fd8, 0x1fdb, 1}, - { 0x1fe8, 0x1fec, 1}, - { 0x1ff8, 0x1ffb, 1}, - { 0x2102, 0x2107, 5}, - { 0x210b, 0x210d, 1}, - { 0x2110, 0x2112, 1}, - { 0x2115, 0x2115, 1}, - { 0x2119, 0x211d, 1}, - { 0x2124, 0x2128, 2}, - { 0x212a, 0x212d, 1}, - { 0x2130, 0x2133, 1}, - { 0x213e, 0x213f, 1}, - { 0x2145, 0x2183, 62}, - { 0x2c00, 0x2c2e, 1}, - { 0x2c60, 0x2c60, 1}, - { 0x2c62, 0x2c64, 1}, - { 0x2c67, 0x2c6b, 2}, - { 0x2c6d, 0x2c6f, 1}, - { 0x2c72, 0x2c75, 3}, - { 0x2c80, 0x2ce2, 2}, - { 0xa640, 0xa65e, 2}, - { 0xa662, 0xa66c, 2}, - { 0xa680, 0xa696, 2}, - { 0xa722, 0xa72e, 2}, - { 0xa732, 0xa76e, 2}, - { 0xa779, 0xa77b, 2}, - { 0xa77d, 0xa77e, 1}, - { 0xa780, 0xa786, 2}, - { 0xa78b, 0xa78b, 1}, - { 0xff21, 0xff3a, 1}, - { 0x10400, 0x10427, 1}, - { 0x1d400, 0x1d419, 1}, - { 0x1d434, 0x1d44d, 1}, - { 0x1d468, 0x1d481, 1}, - { 0x1d49c, 0x1d49c, 1}, - { 0x1d49e, 0x1d49f, 1}, - { 0x1d4a2, 0x1d4a2, 1}, - { 0x1d4a5, 0x1d4a6, 1}, - { 0x1d4a9, 0x1d4ac, 1}, - { 0x1d4ae, 0x1d4b5, 1}, - { 0x1d4d0, 0x1d4e9, 1}, - { 0x1d504, 0x1d505, 1}, - { 0x1d507, 0x1d50a, 1}, - { 0x1d50d, 0x1d514, 1}, - { 0x1d516, 0x1d51c, 1}, - { 0x1d538, 0x1d539, 1}, - { 0x1d53b, 0x1d53e, 1}, - { 0x1d540, 0x1d544, 1}, - { 0x1d546, 0x1d546, 1}, - { 0x1d54a, 0x1d550, 1}, - { 0x1d56c, 0x1d585, 1}, - { 0x1d5a0, 0x1d5b9, 1}, - { 0x1d5d4, 0x1d5ed, 1}, - { 0x1d608, 0x1d621, 1}, - { 0x1d63c, 0x1d655, 1}, - { 0x1d670, 0x1d689, 1}, - { 0x1d6a8, 0x1d6c0, 1}, - { 0x1d6e2, 0x1d6fa, 1}, - { 0x1d71c, 0x1d734, 1}, - { 0x1d756, 0x1d76e, 1}, - { 0x1d790, 0x1d7a8, 1}, - { 0x1d7ca, 0x1d7ca, 1}, -}; - -// Return true if C is in RANGES. - -bool -Lex::is_in_unicode_range(unsigned int c, const Unicode_range* ranges, - size_t range_size) -{ - if (c < 0x100) - { - // The common case is a small value, and we know that it will be - // in the first few entries of the table. Do a linear scan - // rather than a binary search. - for (size_t i = 0; i < range_size; ++i) - { - const Unicode_range* p = &ranges[i]; - if (c <= p->high) - { - if (c < p->low) - return false; - return (c - p->low) % p->stride == 0; - } - } - return false; - } - else - { - size_t lo = 0; - size_t hi = range_size; - while (lo < hi) - { - size_t mid = lo + (hi - lo) / 2; - const Unicode_range* p = &ranges[mid]; - if (c < p->low) - hi = mid; - else if (c > p->high) - lo = mid + 1; - else - return (c - p->low) % p->stride == 0; - } - return false; - } -} - -// Return whether C is a space character. - -bool -Lex::is_unicode_space(unsigned int c) -{ - return Lex::is_in_unicode_range(c, unicode_space, - ARRAY_SIZE(unicode_space)); -} - -// Return whether C is a Unicode digit--a Unicode code point -// classified as "Digit". - -bool -Lex::is_unicode_digit(unsigned int c) -{ - return Lex::is_in_unicode_range(c, unicode_digits, - ARRAY_SIZE(unicode_digits)); -} - -// Return whether C is a Unicode letter--a Unicode code point -// classified as "Letter". - -bool -Lex::is_unicode_letter(unsigned int c) -{ - return Lex::is_in_unicode_range(c, unicode_letters, - ARRAY_SIZE(unicode_letters)); -} - -// Return whether C is a Unicode uppercase letter. a Unicode code -// point classified as "Letter, uppercase". - -bool -Lex::is_unicode_uppercase(unsigned int c) -{ - return Lex::is_in_unicode_range(c, unicode_uppercase_letters, - ARRAY_SIZE(unicode_uppercase_letters)); -} - -// Return whether the identifier NAME should be exported. NAME is a -// mangled name which includes only ASCII characters. - -bool -Lex::is_exported_name(const std::string& name) -{ - unsigned char c = name[0]; - if (c != '$') - return c >= 'A' && c <= 'Z'; - else - { - const char* p = name.data(); - size_t len = name.length(); - if (len < 2 || p[1] != 'U') - return false; - unsigned int ci = 0; - for (size_t i = 2; i < len && p[i] != '$'; ++i) - { - c = p[i]; - if (!hex_p(c)) - return false; - ci <<= 4; - ci |= hex_value(c); - } - return Lex::is_unicode_uppercase(ci); - } -} - -// Return whether the identifier NAME contains an invalid character. -// This is based on how we handle invalid characters in -// gather_identifier. - -bool -Lex::is_invalid_identifier(const std::string& name) -{ - return name.find("$INVALID$") != std::string::npos; -} diff --git a/gcc-4.8.1/gcc/go/gofrontend/lex.h b/gcc-4.8.1/gcc/go/gofrontend/lex.h deleted file mode 100644 index 383a91787..000000000 --- a/gcc-4.8.1/gcc/go/gofrontend/lex.h +++ /dev/null @@ -1,502 +0,0 @@ -// lex.h -- Go frontend lexer. -*- C++ -*- - -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#ifndef GO_LEX_H -#define GO_LEX_H - -#include <mpfr.h> - -#include "operator.h" -#include "go-linemap.h" - -struct Unicode_range; - -// The keywords. These must be in sorted order, other than -// KEYWORD_INVALID. They must match the Keywords::mapping_ array in -// lex.cc. - -enum Keyword -{ - KEYWORD_INVALID, // Not a keyword. - KEYWORD_ASM, - KEYWORD_BREAK, - KEYWORD_CASE, - KEYWORD_CHAN, - KEYWORD_CONST, - KEYWORD_CONTINUE, - KEYWORD_DEFAULT, - KEYWORD_DEFER, - KEYWORD_ELSE, - KEYWORD_FALLTHROUGH, - KEYWORD_FOR, - KEYWORD_FUNC, - KEYWORD_GO, - KEYWORD_GOTO, - KEYWORD_IF, - KEYWORD_IMPORT, - KEYWORD_INTERFACE, - KEYWORD_MAP, - KEYWORD_PACKAGE, - KEYWORD_RANGE, - KEYWORD_RETURN, - KEYWORD_SELECT, - KEYWORD_STRUCT, - KEYWORD_SWITCH, - KEYWORD_TYPE, - KEYWORD_VAR -}; - -// A token returned from the lexer. - -class Token -{ - public: - // Token classification. - enum Classification - { - // Token is invalid. - TOKEN_INVALID, - // Token indicates end of input. - TOKEN_EOF, - // Token is a keyword. - TOKEN_KEYWORD, - // Token is an identifier. - TOKEN_IDENTIFIER, - // Token is a string of characters. - TOKEN_STRING, - // Token is an operator. - TOKEN_OPERATOR, - // Token is a character constant. - TOKEN_CHARACTER, - // Token is an integer. - TOKEN_INTEGER, - // Token is a floating point number. - TOKEN_FLOAT, - // Token is an imaginary number. - TOKEN_IMAGINARY - }; - - ~Token(); - Token(const Token&); - Token& operator=(const Token&); - - // Get token classification. - Classification - classification() const - { return this->classification_; } - - // Make a token for an invalid value. - static Token - make_invalid_token(Location location) - { return Token(TOKEN_INVALID, location); } - - // Make a token representing end of file. - static Token - make_eof_token(Location location) - { return Token(TOKEN_EOF, location); } - - // Make a keyword token. - static Token - make_keyword_token(Keyword keyword, Location location) - { - Token tok(TOKEN_KEYWORD, location); - tok.u_.keyword = keyword; - return tok; - } - - // Make an identifier token. - static Token - make_identifier_token(const std::string& value, bool is_exported, - Location location) - { - Token tok(TOKEN_IDENTIFIER, location); - tok.u_.identifier_value.name = new std::string(value); - tok.u_.identifier_value.is_exported = is_exported; - return tok; - } - - // Make a quoted string token. - static Token - make_string_token(const std::string& value, Location location) - { - Token tok(TOKEN_STRING, location); - tok.u_.string_value = new std::string(value); - return tok; - } - - // Make an operator token. - static Token - make_operator_token(Operator op, Location location) - { - Token tok(TOKEN_OPERATOR, location); - tok.u_.op = op; - return tok; - } - - // Make a character constant token. - static Token - make_character_token(mpz_t val, Location location) - { - Token tok(TOKEN_CHARACTER, location); - mpz_init(tok.u_.integer_value); - mpz_swap(tok.u_.integer_value, val); - return tok; - } - - // Make an integer token. - static Token - make_integer_token(mpz_t val, Location location) - { - Token tok(TOKEN_INTEGER, location); - mpz_init(tok.u_.integer_value); - mpz_swap(tok.u_.integer_value, val); - return tok; - } - - // Make a float token. - static Token - make_float_token(mpfr_t val, Location location) - { - Token tok(TOKEN_FLOAT, location); - mpfr_init(tok.u_.float_value); - mpfr_swap(tok.u_.float_value, val); - return tok; - } - - // Make a token for an imaginary number. - static Token - make_imaginary_token(mpfr_t val, Location location) - { - Token tok(TOKEN_IMAGINARY, location); - mpfr_init(tok.u_.float_value); - mpfr_swap(tok.u_.float_value, val); - return tok; - } - - // Get the location of the token. - Location - location() const - { return this->location_; } - - // Return whether this is an invalid token. - bool - is_invalid() const - { return this->classification_ == TOKEN_INVALID; } - - // Return whether this is the EOF token. - bool - is_eof() const - { return this->classification_ == TOKEN_EOF; } - - // Return the keyword value for a keyword token. - Keyword - keyword() const - { - go_assert(this->classification_ == TOKEN_KEYWORD); - return this->u_.keyword; - } - - // Return whether this is an identifier. - bool - is_identifier() const - { return this->classification_ == TOKEN_IDENTIFIER; } - - // Return the identifier. - const std::string& - identifier() const - { - go_assert(this->classification_ == TOKEN_IDENTIFIER); - return *this->u_.identifier_value.name; - } - - // Return whether the identifier is exported. - bool - is_identifier_exported() const - { - go_assert(this->classification_ == TOKEN_IDENTIFIER); - return this->u_.identifier_value.is_exported; - } - - // Return whether this is a string. - bool - is_string() const - { - return this->classification_ == TOKEN_STRING; - } - - // Return the value of a string. The returned value is a string of - // UTF-8 characters. - std::string - string_value() const - { - go_assert(this->classification_ == TOKEN_STRING); - return *this->u_.string_value; - } - - // Return the value of a character constant. - const mpz_t* - character_value() const - { - go_assert(this->classification_ == TOKEN_CHARACTER); - return &this->u_.integer_value; - } - - // Return the value of an integer. - const mpz_t* - integer_value() const - { - go_assert(this->classification_ == TOKEN_INTEGER); - return &this->u_.integer_value; - } - - // Return the value of a float. - const mpfr_t* - float_value() const - { - go_assert(this->classification_ == TOKEN_FLOAT); - return &this->u_.float_value; - } - - // Return the value of an imaginary number. - const mpfr_t* - imaginary_value() const - { - go_assert(this->classification_ == TOKEN_IMAGINARY); - return &this->u_.float_value; - } - - // Return the operator value for an operator token. - Operator - op() const - { - go_assert(this->classification_ == TOKEN_OPERATOR); - return this->u_.op; - } - - // Return whether this token is KEYWORD. - bool - is_keyword(Keyword keyword) const - { - return (this->classification_ == TOKEN_KEYWORD - && this->u_.keyword == keyword); - } - - // Return whether this token is OP. - bool - is_op(Operator op) const - { return this->classification_ == TOKEN_OPERATOR && this->u_.op == op; } - - // Print the token for debugging. - void - print(FILE*) const; - - private: - // Private constructor used by make_..._token functions above. - Token(Classification, Location); - - // Clear the token. - void - clear(); - - // The token classification. - Classification classification_; - union - { - // The keyword value for TOKEN_KEYWORD. - Keyword keyword; - // The token value for TOKEN_IDENTIFIER. - struct - { - // The name of the identifier. This has been mangled to only - // include ASCII characters. - std::string* name; - // Whether this name should be exported. This is true if the - // first letter in the name is upper case. - bool is_exported; - } identifier_value; - // The string value for TOKEN_STRING. - std::string* string_value; - // The token value for TOKEN_CHARACTER or TOKEN_INTEGER. - mpz_t integer_value; - // The token value for TOKEN_FLOAT or TOKEN_IMAGINARY. - mpfr_t float_value; - // The token value for TOKEN_OPERATOR or the keyword value - Operator op; - } u_; - // The source location. - Location location_; -}; - -// The lexer itself. - -class Lex -{ - public: - Lex(const char* input_file_name, FILE* input_file, Linemap *linemap); - - ~Lex(); - - // Return the next token. - Token - next_token(); - - // Return the contents of any current //extern comment. - const std::string& - extern_name() const - { return this->extern_; } - - // Return whether we have seen a //go:nointerface comment, clearing - // the flag. - bool - get_and_clear_nointerface() - { - bool ret = this->saw_nointerface_; - this->saw_nointerface_ = false; - return ret; - } - - // Return whether the identifier NAME should be exported. NAME is a - // mangled name which includes only ASCII characters. - static bool - is_exported_name(const std::string& name); - - // Return whether the identifier NAME is invalid. When we see an - // invalid character we still build an identifier, but we use a - // magic string to indicate that the identifier is invalid. We then - // use this to avoid knockon errors. - static bool - is_invalid_identifier(const std::string& name); - - // A helper function. Append V to STR. IS_CHARACTER is true if V - // is a Unicode character which should be converted into UTF-8, - // false if it is a byte value to be appended directly. The - // location is used to warn about an out of range character. - static void - append_char(unsigned int v, bool is_charater, std::string* str, - Location); - - // A helper function. Fetch a UTF-8 character from STR and store it - // in *VALUE. Return the number of bytes read from STR. Return 0 - // if STR does not point to a valid UTF-8 character. - static int - fetch_char(const char* str, unsigned int *value); - - // Return whether C is a Unicode or "C" locale space character. - static bool - is_unicode_space(unsigned int c); - - private: - ssize_t - get_line(); - - bool - require_line(); - - // The current location. - Location - location() const; - - // A position CHARS column positions before the current location. - Location - earlier_location(int chars) const; - - static bool - is_hex_digit(char); - - static unsigned char - octal_value(char c) - { return c - '0'; } - - Token - make_invalid_token() - { return Token::make_invalid_token(this->location()); } - - Token - make_eof_token() - { return Token::make_eof_token(this->location()); } - - Token - make_operator(Operator op, int chars) - { return Token::make_operator_token(op, this->earlier_location(chars)); } - - Token - gather_identifier(); - - static bool - could_be_exponent(const char*, const char*); - - Token - gather_number(); - - Token - gather_character(); - - Token - gather_string(); - - Token - gather_raw_string(); - - const char* - advance_one_utf8_char(const char*, unsigned int*, bool*); - - const char* - advance_one_char(const char*, bool, unsigned int*, bool*); - - static bool - is_unicode_digit(unsigned int c); - - static bool - is_unicode_letter(unsigned int c); - - static bool - is_unicode_uppercase(unsigned int c); - - static bool - is_in_unicode_range(unsigned int C, const Unicode_range* ranges, - size_t range_size); - - Operator - three_character_operator(char, char, char); - - Operator - two_character_operator(char, char); - - Operator - one_character_operator(char); - - bool - skip_c_comment(); - - void - skip_cpp_comment(); - - // The input file name. - const char* input_file_name_; - // The input file. - FILE* input_file_; - // The object used to keep track of file names and line numbers. - Linemap* linemap_; - // The line buffer. This holds the current line. - char* linebuf_; - // The size of the line buffer. - size_t linebufsize_; - // The nmber of characters in the current line. - size_t linesize_; - // The current offset in linebuf_. - size_t lineoff_; - // The current line number. - size_t lineno_; - // Whether to add a semicolon if we see a newline now. - bool add_semi_at_eol_; - // Whether we just saw a magic go:nointerface comment. - bool saw_nointerface_; - // The external name to use for a function declaration, from a magic - // //extern comment. - std::string extern_; -}; - -#endif // !defined(GO_LEX_H) diff --git a/gcc-4.8.1/gcc/go/gofrontend/operator.h b/gcc-4.8.1/gcc/go/gofrontend/operator.h deleted file mode 100644 index f3e0fd074..000000000 --- a/gcc-4.8.1/gcc/go/gofrontend/operator.h +++ /dev/null @@ -1,66 +0,0 @@ -// operator.h -- Go frontend operators. -*- C++ -*- - -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#ifndef GO_OPERATOR_H -#define GO_OPERATOR_H - -// The operators. - -enum Operator -{ - OPERATOR_INVALID, - OPERATOR_OROR, // || - OPERATOR_ANDAND, // && - OPERATOR_EQEQ, // == - OPERATOR_NOTEQ, // != - OPERATOR_LT, // < - OPERATOR_LE, // <= - OPERATOR_GT, // > - OPERATOR_GE, // >= - OPERATOR_PLUS, // + - OPERATOR_MINUS, // - - OPERATOR_OR, // | - OPERATOR_XOR, // ^ - OPERATOR_MULT, // * - OPERATOR_DIV, // / - OPERATOR_MOD, // % - OPERATOR_LSHIFT, // << - OPERATOR_RSHIFT, // >> - OPERATOR_AND, // & - OPERATOR_NOT, // ! - OPERATOR_BITCLEAR, // &^ - OPERATOR_CHANOP, // <- - - OPERATOR_EQ, // = - OPERATOR_PLUSEQ, // += - OPERATOR_MINUSEQ, // -= - OPERATOR_OREQ, // |= - OPERATOR_XOREQ, // ^= - OPERATOR_MULTEQ, // *= - OPERATOR_DIVEQ, // /= - OPERATOR_MODEQ, // %= - OPERATOR_LSHIFTEQ, // <<= - OPERATOR_RSHIFTEQ, // >>= - OPERATOR_ANDEQ, // &= - OPERATOR_BITCLEAREQ, // &^= - OPERATOR_PLUSPLUS, // ++ - OPERATOR_MINUSMINUS, // -- - - OPERATOR_COLON, // : - OPERATOR_COLONEQ, // := - OPERATOR_SEMICOLON, // ; - OPERATOR_DOT, // . - OPERATOR_ELLIPSIS, // ... - OPERATOR_COMMA, // , - OPERATOR_LPAREN, // ( - OPERATOR_RPAREN, // ) - OPERATOR_LCURLY, // { - OPERATOR_RCURLY, // } - OPERATOR_LSQUARE, // [ - OPERATOR_RSQUARE // ] -}; - -#endif // !defined(GO_OPERATOR_H) diff --git a/gcc-4.8.1/gcc/go/gofrontend/parse.cc b/gcc-4.8.1/gcc/go/gofrontend/parse.cc deleted file mode 100644 index d7a18d023..000000000 --- a/gcc-4.8.1/gcc/go/gofrontend/parse.cc +++ /dev/null @@ -1,5676 +0,0 @@ -// parse.cc -- Go frontend parser. - -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "go-system.h" - -#include "lex.h" -#include "gogo.h" -#include "types.h" -#include "statements.h" -#include "expressions.h" -#include "parse.h" - -// Struct Parse::Enclosing_var_comparison. - -// Return true if v1 should be considered to be less than v2. - -bool -Parse::Enclosing_var_comparison::operator()(const Enclosing_var& v1, - const Enclosing_var& v2) -{ - if (v1.var() == v2.var()) - return false; - - const std::string& n1(v1.var()->name()); - const std::string& n2(v2.var()->name()); - int i = n1.compare(n2); - if (i < 0) - return true; - else if (i > 0) - return false; - - // If we get here it means that a single nested function refers to - // two different variables defined in enclosing functions, and both - // variables have the same name. I think this is impossible. - go_unreachable(); -} - -// Class Parse. - -Parse::Parse(Lex* lex, Gogo* gogo) - : lex_(lex), - token_(Token::make_invalid_token(Linemap::unknown_location())), - unget_token_(Token::make_invalid_token(Linemap::unknown_location())), - unget_token_valid_(false), - is_erroneous_function_(false), - gogo_(gogo), - break_stack_(NULL), - continue_stack_(NULL), - iota_(0), - enclosing_vars_(), - type_switch_vars_() -{ -} - -// Return the current token. - -const Token* -Parse::peek_token() -{ - if (this->unget_token_valid_) - return &this->unget_token_; - if (this->token_.is_invalid()) - this->token_ = this->lex_->next_token(); - return &this->token_; -} - -// Advance to the next token and return it. - -const Token* -Parse::advance_token() -{ - if (this->unget_token_valid_) - { - this->unget_token_valid_ = false; - if (!this->token_.is_invalid()) - return &this->token_; - } - this->token_ = this->lex_->next_token(); - return &this->token_; -} - -// Push a token back on the input stream. - -void -Parse::unget_token(const Token& token) -{ - go_assert(!this->unget_token_valid_); - this->unget_token_ = token; - this->unget_token_valid_ = true; -} - -// The location of the current token. - -Location -Parse::location() -{ - return this->peek_token()->location(); -} - -// IdentifierList = identifier { "," identifier } . - -void -Parse::identifier_list(Typed_identifier_list* til) -{ - const Token* token = this->peek_token(); - while (true) - { - if (!token->is_identifier()) - { - error_at(this->location(), "expected identifier"); - return; - } - std::string name = - this->gogo_->pack_hidden_name(token->identifier(), - token->is_identifier_exported()); - til->push_back(Typed_identifier(name, NULL, token->location())); - token = this->advance_token(); - if (!token->is_op(OPERATOR_COMMA)) - return; - token = this->advance_token(); - } -} - -// ExpressionList = Expression { "," Expression } . - -// If MAY_BE_COMPOSITE_LIT is true, an expression may be a composite -// literal. - -// If MAY_BE_SINK is true, the expressions in the list may be "_". - -Expression_list* -Parse::expression_list(Expression* first, bool may_be_sink, - bool may_be_composite_lit) -{ - Expression_list* ret = new Expression_list(); - if (first != NULL) - ret->push_back(first); - while (true) - { - ret->push_back(this->expression(PRECEDENCE_NORMAL, may_be_sink, - may_be_composite_lit, NULL, NULL)); - - const Token* token = this->peek_token(); - if (!token->is_op(OPERATOR_COMMA)) - return ret; - - // Most expression lists permit a trailing comma. - Location location = token->location(); - this->advance_token(); - if (!this->expression_may_start_here()) - { - this->unget_token(Token::make_operator_token(OPERATOR_COMMA, - location)); - return ret; - } - } -} - -// QualifiedIdent = [ PackageName "." ] identifier . -// PackageName = identifier . - -// This sets *PNAME to the identifier and sets *PPACKAGE to the -// package or NULL if there isn't one. This returns true on success, -// false on failure in which case it will have emitted an error -// message. - -bool -Parse::qualified_ident(std::string* pname, Named_object** ppackage) -{ - const Token* token = this->peek_token(); - if (!token->is_identifier()) - { - error_at(this->location(), "expected identifier"); - return false; - } - - std::string name = token->identifier(); - bool is_exported = token->is_identifier_exported(); - name = this->gogo_->pack_hidden_name(name, is_exported); - - token = this->advance_token(); - if (!token->is_op(OPERATOR_DOT)) - { - *pname = name; - *ppackage = NULL; - return true; - } - - Named_object* package = this->gogo_->lookup(name, NULL); - if (package == NULL || !package->is_package()) - { - error_at(this->location(), "expected package"); - // We expect . IDENTIFIER; skip both. - if (this->advance_token()->is_identifier()) - this->advance_token(); - return false; - } - - package->package_value()->set_used(); - - token = this->advance_token(); - if (!token->is_identifier()) - { - error_at(this->location(), "expected identifier"); - return false; - } - - name = token->identifier(); - - if (name == "_") - { - error_at(this->location(), "invalid use of %<_%>"); - name = "blank"; - } - - if (package->name() == this->gogo_->package_name()) - name = this->gogo_->pack_hidden_name(name, - token->is_identifier_exported()); - - *pname = name; - *ppackage = package; - - this->advance_token(); - - return true; -} - -// Type = TypeName | TypeLit | "(" Type ")" . -// TypeLit = -// ArrayType | StructType | PointerType | FunctionType | InterfaceType | -// SliceType | MapType | ChannelType . - -Type* -Parse::type() -{ - const Token* token = this->peek_token(); - if (token->is_identifier()) - return this->type_name(true); - else if (token->is_op(OPERATOR_LSQUARE)) - return this->array_type(false); - else if (token->is_keyword(KEYWORD_CHAN) - || token->is_op(OPERATOR_CHANOP)) - return this->channel_type(); - else if (token->is_keyword(KEYWORD_INTERFACE)) - return this->interface_type(); - else if (token->is_keyword(KEYWORD_FUNC)) - { - Location location = token->location(); - this->advance_token(); - Type* type = this->signature(NULL, location); - if (type == NULL) - return Type::make_error_type(); - return type; - } - else if (token->is_keyword(KEYWORD_MAP)) - return this->map_type(); - else if (token->is_keyword(KEYWORD_STRUCT)) - return this->struct_type(); - else if (token->is_op(OPERATOR_MULT)) - return this->pointer_type(); - else if (token->is_op(OPERATOR_LPAREN)) - { - this->advance_token(); - Type* ret = this->type(); - if (this->peek_token()->is_op(OPERATOR_RPAREN)) - this->advance_token(); - else - { - if (!ret->is_error_type()) - error_at(this->location(), "expected %<)%>"); - } - return ret; - } - else - { - error_at(token->location(), "expected type"); - return Type::make_error_type(); - } -} - -bool -Parse::type_may_start_here() -{ - const Token* token = this->peek_token(); - return (token->is_identifier() - || token->is_op(OPERATOR_LSQUARE) - || token->is_op(OPERATOR_CHANOP) - || token->is_keyword(KEYWORD_CHAN) - || token->is_keyword(KEYWORD_INTERFACE) - || token->is_keyword(KEYWORD_FUNC) - || token->is_keyword(KEYWORD_MAP) - || token->is_keyword(KEYWORD_STRUCT) - || token->is_op(OPERATOR_MULT) - || token->is_op(OPERATOR_LPAREN)); -} - -// TypeName = QualifiedIdent . - -// If MAY_BE_NIL is true, then an identifier with the value of the -// predefined constant nil is accepted, returning the nil type. - -Type* -Parse::type_name(bool issue_error) -{ - Location location = this->location(); - - std::string name; - Named_object* package; - if (!this->qualified_ident(&name, &package)) - return Type::make_error_type(); - - Named_object* named_object; - if (package == NULL) - named_object = this->gogo_->lookup(name, NULL); - else - { - named_object = package->package_value()->lookup(name); - if (named_object == NULL - && issue_error - && package->name() != this->gogo_->package_name()) - { - // Check whether the name is there but hidden. - std::string s = ('.' + package->package_value()->pkgpath() - + '.' + name); - named_object = package->package_value()->lookup(s); - if (named_object != NULL) - { - Package* p = package->package_value(); - const std::string& packname(p->package_name()); - error_at(location, "invalid reference to hidden type %<%s.%s%>", - Gogo::message_name(packname).c_str(), - Gogo::message_name(name).c_str()); - issue_error = false; - } - } - } - - bool ok = true; - if (named_object == NULL) - { - if (package == NULL) - named_object = this->gogo_->add_unknown_name(name, location); - else - { - const std::string& packname(package->package_value()->package_name()); - error_at(location, "reference to undefined identifier %<%s.%s%>", - Gogo::message_name(packname).c_str(), - Gogo::message_name(name).c_str()); - issue_error = false; - ok = false; - } - } - else if (named_object->is_type()) - { - if (!named_object->type_value()->is_visible()) - ok = false; - } - else if (named_object->is_unknown() || named_object->is_type_declaration()) - ; - else - ok = false; - - if (!ok) - { - if (issue_error) - error_at(location, "expected type"); - return Type::make_error_type(); - } - - if (named_object->is_type()) - return named_object->type_value(); - else if (named_object->is_unknown() || named_object->is_type_declaration()) - return Type::make_forward_declaration(named_object); - else - go_unreachable(); -} - -// ArrayType = "[" [ ArrayLength ] "]" ElementType . -// ArrayLength = Expression . -// ElementType = CompleteType . - -Type* -Parse::array_type(bool may_use_ellipsis) -{ - go_assert(this->peek_token()->is_op(OPERATOR_LSQUARE)); - const Token* token = this->advance_token(); - - Expression* length = NULL; - if (token->is_op(OPERATOR_RSQUARE)) - this->advance_token(); - else - { - if (!token->is_op(OPERATOR_ELLIPSIS)) - length = this->expression(PRECEDENCE_NORMAL, false, true, NULL, NULL); - else if (may_use_ellipsis) - { - // An ellipsis is used in composite literals to represent a - // fixed array of the size of the number of elements. We - // use a length of nil to represent this, and change the - // length when parsing the composite literal. - length = Expression::make_nil(this->location()); - this->advance_token(); - } - else - { - error_at(this->location(), - "use of %<[...]%> outside of array literal"); - length = Expression::make_error(this->location()); - this->advance_token(); - } - if (!this->peek_token()->is_op(OPERATOR_RSQUARE)) - { - error_at(this->location(), "expected %<]%>"); - return Type::make_error_type(); - } - this->advance_token(); - } - - Type* element_type = this->type(); - - return Type::make_array_type(element_type, length); -} - -// MapType = "map" "[" KeyType "]" ValueType . -// KeyType = CompleteType . -// ValueType = CompleteType . - -Type* -Parse::map_type() -{ - Location location = this->location(); - go_assert(this->peek_token()->is_keyword(KEYWORD_MAP)); - if (!this->advance_token()->is_op(OPERATOR_LSQUARE)) - { - error_at(this->location(), "expected %<[%>"); - return Type::make_error_type(); - } - this->advance_token(); - - Type* key_type = this->type(); - - if (!this->peek_token()->is_op(OPERATOR_RSQUARE)) - { - error_at(this->location(), "expected %<]%>"); - return Type::make_error_type(); - } - this->advance_token(); - - Type* value_type = this->type(); - - if (key_type->is_error_type() || value_type->is_error_type()) - return Type::make_error_type(); - - return Type::make_map_type(key_type, value_type, location); -} - -// StructType = "struct" "{" { FieldDecl ";" } "}" . - -Type* -Parse::struct_type() -{ - go_assert(this->peek_token()->is_keyword(KEYWORD_STRUCT)); - Location location = this->location(); - if (!this->advance_token()->is_op(OPERATOR_LCURLY)) - { - Location token_loc = this->location(); - if (this->peek_token()->is_op(OPERATOR_SEMICOLON) - && this->advance_token()->is_op(OPERATOR_LCURLY)) - error_at(token_loc, "unexpected semicolon or newline before %<{%>"); - else - { - error_at(this->location(), "expected %<{%>"); - return Type::make_error_type(); - } - } - this->advance_token(); - - Struct_field_list* sfl = new Struct_field_list; - while (!this->peek_token()->is_op(OPERATOR_RCURLY)) - { - this->field_decl(sfl); - if (this->peek_token()->is_op(OPERATOR_SEMICOLON)) - this->advance_token(); - else if (!this->peek_token()->is_op(OPERATOR_RCURLY)) - { - error_at(this->location(), "expected %<;%> or %<}%> or newline"); - if (!this->skip_past_error(OPERATOR_RCURLY)) - return Type::make_error_type(); - } - } - this->advance_token(); - - for (Struct_field_list::const_iterator pi = sfl->begin(); - pi != sfl->end(); - ++pi) - { - if (pi->type()->is_error_type()) - return pi->type(); - for (Struct_field_list::const_iterator pj = pi + 1; - pj != sfl->end(); - ++pj) - { - if (pi->field_name() == pj->field_name() - && !Gogo::is_sink_name(pi->field_name())) - error_at(pi->location(), "duplicate field name %<%s%>", - Gogo::message_name(pi->field_name()).c_str()); - } - } - - return Type::make_struct_type(sfl, location); -} - -// FieldDecl = (IdentifierList CompleteType | TypeName) [ Tag ] . -// Tag = string_lit . - -void -Parse::field_decl(Struct_field_list* sfl) -{ - const Token* token = this->peek_token(); - Location location = token->location(); - bool is_anonymous; - bool is_anonymous_pointer; - if (token->is_op(OPERATOR_MULT)) - { - is_anonymous = true; - is_anonymous_pointer = true; - } - else if (token->is_identifier()) - { - std::string id = token->identifier(); - bool is_id_exported = token->is_identifier_exported(); - Location id_location = token->location(); - token = this->advance_token(); - is_anonymous = (token->is_op(OPERATOR_SEMICOLON) - || token->is_op(OPERATOR_RCURLY) - || token->is_op(OPERATOR_DOT) - || token->is_string()); - is_anonymous_pointer = false; - this->unget_token(Token::make_identifier_token(id, is_id_exported, - id_location)); - } - else - { - error_at(this->location(), "expected field name"); - this->gogo_->mark_locals_used(); - while (!token->is_op(OPERATOR_SEMICOLON) - && !token->is_op(OPERATOR_RCURLY) - && !token->is_eof()) - token = this->advance_token(); - return; - } - - if (is_anonymous) - { - if (is_anonymous_pointer) - { - this->advance_token(); - if (!this->peek_token()->is_identifier()) - { - error_at(this->location(), "expected field name"); - this->gogo_->mark_locals_used(); - while (!token->is_op(OPERATOR_SEMICOLON) - && !token->is_op(OPERATOR_RCURLY) - && !token->is_eof()) - token = this->advance_token(); - return; - } - } - Type* type = this->type_name(true); - - std::string tag; - if (this->peek_token()->is_string()) - { - tag = this->peek_token()->string_value(); - this->advance_token(); - } - - if (!type->is_error_type()) - { - if (is_anonymous_pointer) - type = Type::make_pointer_type(type); - sfl->push_back(Struct_field(Typed_identifier("", type, location))); - if (!tag.empty()) - sfl->back().set_tag(tag); - } - } - else - { - Typed_identifier_list til; - while (true) - { - token = this->peek_token(); - if (!token->is_identifier()) - { - error_at(this->location(), "expected identifier"); - return; - } - std::string name = - this->gogo_->pack_hidden_name(token->identifier(), - token->is_identifier_exported()); - til.push_back(Typed_identifier(name, NULL, token->location())); - if (!this->advance_token()->is_op(OPERATOR_COMMA)) - break; - this->advance_token(); - } - - Type* type = this->type(); - - std::string tag; - if (this->peek_token()->is_string()) - { - tag = this->peek_token()->string_value(); - this->advance_token(); - } - - for (Typed_identifier_list::iterator p = til.begin(); - p != til.end(); - ++p) - { - p->set_type(type); - sfl->push_back(Struct_field(*p)); - if (!tag.empty()) - sfl->back().set_tag(tag); - } - } -} - -// PointerType = "*" Type . - -Type* -Parse::pointer_type() -{ - go_assert(this->peek_token()->is_op(OPERATOR_MULT)); - this->advance_token(); - Type* type = this->type(); - if (type->is_error_type()) - return type; - return Type::make_pointer_type(type); -} - -// ChannelType = Channel | SendChannel | RecvChannel . -// Channel = "chan" ElementType . -// SendChannel = "chan" "<-" ElementType . -// RecvChannel = "<-" "chan" ElementType . - -Type* -Parse::channel_type() -{ - const Token* token = this->peek_token(); - bool send = true; - bool receive = true; - if (token->is_op(OPERATOR_CHANOP)) - { - if (!this->advance_token()->is_keyword(KEYWORD_CHAN)) - { - error_at(this->location(), "expected %<chan%>"); - return Type::make_error_type(); - } - send = false; - this->advance_token(); - } - else - { - go_assert(token->is_keyword(KEYWORD_CHAN)); - if (this->advance_token()->is_op(OPERATOR_CHANOP)) - { - receive = false; - this->advance_token(); - } - } - - // Better error messages for the common error of omitting the - // channel element type. - if (!this->type_may_start_here()) - { - token = this->peek_token(); - if (token->is_op(OPERATOR_RCURLY)) - error_at(this->location(), "unexpected %<}%> in channel type"); - else if (token->is_op(OPERATOR_RPAREN)) - error_at(this->location(), "unexpected %<)%> in channel type"); - else if (token->is_op(OPERATOR_COMMA)) - error_at(this->location(), "unexpected comma in channel type"); - else - error_at(this->location(), "expected channel element type"); - return Type::make_error_type(); - } - - Type* element_type = this->type(); - return Type::make_channel_type(send, receive, element_type); -} - -// Give an error for a duplicate parameter or receiver name. - -void -Parse::check_signature_names(const Typed_identifier_list* params, - Parse::Names* names) -{ - for (Typed_identifier_list::const_iterator p = params->begin(); - p != params->end(); - ++p) - { - if (p->name().empty() || Gogo::is_sink_name(p->name())) - continue; - std::pair<std::string, const Typed_identifier*> val = - std::make_pair(p->name(), &*p); - std::pair<Parse::Names::iterator, bool> ins = names->insert(val); - if (!ins.second) - { - error_at(p->location(), "redefinition of %qs", - Gogo::message_name(p->name()).c_str()); - inform(ins.first->second->location(), - "previous definition of %qs was here", - Gogo::message_name(p->name()).c_str()); - } - } -} - -// Signature = Parameters [ Result ] . - -// RECEIVER is the receiver if there is one, or NULL. LOCATION is the -// location of the start of the type. - -// This returns NULL on a parse error. - -Function_type* -Parse::signature(Typed_identifier* receiver, Location location) -{ - bool is_varargs = false; - Typed_identifier_list* params; - bool params_ok = this->parameters(¶ms, &is_varargs); - - Typed_identifier_list* results = NULL; - if (this->peek_token()->is_op(OPERATOR_LPAREN) - || this->type_may_start_here()) - { - if (!this->result(&results)) - return NULL; - } - - if (!params_ok) - return NULL; - - Parse::Names names; - if (params != NULL) - this->check_signature_names(params, &names); - if (results != NULL) - this->check_signature_names(results, &names); - - Function_type* ret = Type::make_function_type(receiver, params, results, - location); - if (is_varargs) - ret->set_is_varargs(); - return ret; -} - -// Parameters = "(" [ ParameterList [ "," ] ] ")" . - -// This returns false on a parse error. - -bool -Parse::parameters(Typed_identifier_list** pparams, bool* is_varargs) -{ - *pparams = NULL; - - if (!this->peek_token()->is_op(OPERATOR_LPAREN)) - { - error_at(this->location(), "expected %<(%>"); - return false; - } - - Typed_identifier_list* params = NULL; - bool saw_error = false; - - const Token* token = this->advance_token(); - if (!token->is_op(OPERATOR_RPAREN)) - { - params = this->parameter_list(is_varargs); - if (params == NULL) - saw_error = true; - token = this->peek_token(); - } - - // The optional trailing comma is picked up in parameter_list. - - if (!token->is_op(OPERATOR_RPAREN)) - error_at(this->location(), "expected %<)%>"); - else - this->advance_token(); - - if (saw_error) - return false; - - *pparams = params; - return true; -} - -// ParameterList = ParameterDecl { "," ParameterDecl } . - -// This sets *IS_VARARGS if the list ends with an ellipsis. -// IS_VARARGS will be NULL if varargs are not permitted. - -// We pick up an optional trailing comma. - -// This returns NULL if some error is seen. - -Typed_identifier_list* -Parse::parameter_list(bool* is_varargs) -{ - Location location = this->location(); - Typed_identifier_list* ret = new Typed_identifier_list(); - - bool saw_error = false; - - // If we see an identifier and then a comma, then we don't know - // whether we are looking at a list of identifiers followed by a - // type, or a list of types given by name. We have to do an - // arbitrary lookahead to figure it out. - - bool parameters_have_names; - const Token* token = this->peek_token(); - if (!token->is_identifier()) - { - // This must be a type which starts with something like '*'. - parameters_have_names = false; - } - else - { - std::string name = token->identifier(); - bool is_exported = token->is_identifier_exported(); - Location location = token->location(); - token = this->advance_token(); - if (!token->is_op(OPERATOR_COMMA)) - { - if (token->is_op(OPERATOR_DOT)) - { - // This is a qualified identifier, which must turn out - // to be a type. - parameters_have_names = false; - } - else if (token->is_op(OPERATOR_RPAREN)) - { - // A single identifier followed by a parenthesis must be - // a type name. - parameters_have_names = false; - } - else - { - // An identifier followed by something other than a - // comma or a dot or a right parenthesis must be a - // parameter name followed by a type. - parameters_have_names = true; - } - - this->unget_token(Token::make_identifier_token(name, is_exported, - location)); - } - else - { - // An identifier followed by a comma may be the first in a - // list of parameter names followed by a type, or it may be - // the first in a list of types without parameter names. To - // find out we gather as many identifiers separated by - // commas as we can. - std::string id_name = this->gogo_->pack_hidden_name(name, - is_exported); - ret->push_back(Typed_identifier(id_name, NULL, location)); - bool just_saw_comma = true; - while (this->advance_token()->is_identifier()) - { - name = this->peek_token()->identifier(); - is_exported = this->peek_token()->is_identifier_exported(); - location = this->peek_token()->location(); - id_name = this->gogo_->pack_hidden_name(name, is_exported); - ret->push_back(Typed_identifier(id_name, NULL, location)); - if (!this->advance_token()->is_op(OPERATOR_COMMA)) - { - just_saw_comma = false; - break; - } - } - - if (just_saw_comma) - { - // We saw ID1 "," ID2 "," followed by something which - // was not an identifier. We must be seeing the start - // of a type, and ID1 and ID2 must be types, and the - // parameters don't have names. - parameters_have_names = false; - } - else if (this->peek_token()->is_op(OPERATOR_RPAREN)) - { - // We saw ID1 "," ID2 ")". ID1 and ID2 must be types, - // and the parameters don't have names. - parameters_have_names = false; - } - else if (this->peek_token()->is_op(OPERATOR_DOT)) - { - // We saw ID1 "," ID2 ".". ID2 must be a package name, - // ID1 must be a type, and the parameters don't have - // names. - parameters_have_names = false; - this->unget_token(Token::make_identifier_token(name, is_exported, - location)); - ret->pop_back(); - just_saw_comma = true; - } - else - { - // We saw ID1 "," ID2 followed by something other than - // ",", ".", or ")". We must be looking at the start of - // a type, and ID1 and ID2 must be parameter names. - parameters_have_names = true; - } - - if (parameters_have_names) - { - go_assert(!just_saw_comma); - // We have just seen ID1, ID2 xxx. - Type* type; - if (!this->peek_token()->is_op(OPERATOR_ELLIPSIS)) - type = this->type(); - else - { - error_at(this->location(), "%<...%> only permits one name"); - saw_error = true; - this->advance_token(); - type = this->type(); - } - for (size_t i = 0; i < ret->size(); ++i) - ret->set_type(i, type); - if (!this->peek_token()->is_op(OPERATOR_COMMA)) - return saw_error ? NULL : ret; - if (this->advance_token()->is_op(OPERATOR_RPAREN)) - return saw_error ? NULL : ret; - } - else - { - Typed_identifier_list* tret = new Typed_identifier_list(); - for (Typed_identifier_list::const_iterator p = ret->begin(); - p != ret->end(); - ++p) - { - Named_object* no = this->gogo_->lookup(p->name(), NULL); - Type* type; - if (no == NULL) - no = this->gogo_->add_unknown_name(p->name(), - p->location()); - - if (no->is_type()) - type = no->type_value(); - else if (no->is_unknown() || no->is_type_declaration()) - type = Type::make_forward_declaration(no); - else - { - error_at(p->location(), "expected %<%s%> to be a type", - Gogo::message_name(p->name()).c_str()); - saw_error = true; - type = Type::make_error_type(); - } - tret->push_back(Typed_identifier("", type, p->location())); - } - delete ret; - ret = tret; - if (!just_saw_comma - || this->peek_token()->is_op(OPERATOR_RPAREN)) - return saw_error ? NULL : ret; - } - } - } - - bool mix_error = false; - this->parameter_decl(parameters_have_names, ret, is_varargs, &mix_error); - while (this->peek_token()->is_op(OPERATOR_COMMA)) - { - if (this->advance_token()->is_op(OPERATOR_RPAREN)) - break; - if (is_varargs != NULL && *is_varargs) - { - error_at(this->location(), "%<...%> must be last parameter"); - saw_error = true; - } - this->parameter_decl(parameters_have_names, ret, is_varargs, &mix_error); - } - if (mix_error) - { - error_at(location, "invalid named/anonymous mix"); - saw_error = true; - } - if (saw_error) - { - delete ret; - return NULL; - } - return ret; -} - -// ParameterDecl = [ IdentifierList ] [ "..." ] Type . - -void -Parse::parameter_decl(bool parameters_have_names, - Typed_identifier_list* til, - bool* is_varargs, - bool* mix_error) -{ - if (!parameters_have_names) - { - Type* type; - Location location = this->location(); - if (!this->peek_token()->is_identifier()) - { - if (!this->peek_token()->is_op(OPERATOR_ELLIPSIS)) - type = this->type(); - else - { - if (is_varargs == NULL) - error_at(this->location(), "invalid use of %<...%>"); - else - *is_varargs = true; - this->advance_token(); - if (is_varargs == NULL - && this->peek_token()->is_op(OPERATOR_RPAREN)) - type = Type::make_error_type(); - else - { - Type* element_type = this->type(); - type = Type::make_array_type(element_type, NULL); - } - } - } - else - { - type = this->type_name(false); - if (type->is_error_type() - || (!this->peek_token()->is_op(OPERATOR_COMMA) - && !this->peek_token()->is_op(OPERATOR_RPAREN))) - { - *mix_error = true; - while (!this->peek_token()->is_op(OPERATOR_COMMA) - && !this->peek_token()->is_op(OPERATOR_RPAREN)) - this->advance_token(); - } - } - if (!type->is_error_type()) - til->push_back(Typed_identifier("", type, location)); - } - else - { - size_t orig_count = til->size(); - if (this->peek_token()->is_identifier()) - this->identifier_list(til); - else - *mix_error = true; - size_t new_count = til->size(); - - Type* type; - if (!this->peek_token()->is_op(OPERATOR_ELLIPSIS)) - type = this->type(); - else - { - if (is_varargs == NULL) - error_at(this->location(), "invalid use of %<...%>"); - else if (new_count > orig_count + 1) - error_at(this->location(), "%<...%> only permits one name"); - else - *is_varargs = true; - this->advance_token(); - Type* element_type = this->type(); - type = Type::make_array_type(element_type, NULL); - } - for (size_t i = orig_count; i < new_count; ++i) - til->set_type(i, type); - } -} - -// Result = Parameters | Type . - -// This returns false on a parse error. - -bool -Parse::result(Typed_identifier_list** presults) -{ - if (this->peek_token()->is_op(OPERATOR_LPAREN)) - return this->parameters(presults, NULL); - else - { - Location location = this->location(); - Type* type = this->type(); - if (type->is_error_type()) - { - *presults = NULL; - return false; - } - Typed_identifier_list* til = new Typed_identifier_list(); - til->push_back(Typed_identifier("", type, location)); - *presults = til; - return true; - } -} - -// Block = "{" [ StatementList ] "}" . - -// Returns the location of the closing brace. - -Location -Parse::block() -{ - if (!this->peek_token()->is_op(OPERATOR_LCURLY)) - { - Location loc = this->location(); - if (this->peek_token()->is_op(OPERATOR_SEMICOLON) - && this->advance_token()->is_op(OPERATOR_LCURLY)) - error_at(loc, "unexpected semicolon or newline before %<{%>"); - else - { - error_at(this->location(), "expected %<{%>"); - return Linemap::unknown_location(); - } - } - - const Token* token = this->advance_token(); - - if (!token->is_op(OPERATOR_RCURLY)) - { - this->statement_list(); - token = this->peek_token(); - if (!token->is_op(OPERATOR_RCURLY)) - { - if (!token->is_eof() || !saw_errors()) - error_at(this->location(), "expected %<}%>"); - - this->gogo_->mark_locals_used(); - - // Skip ahead to the end of the block, in hopes of avoiding - // lots of meaningless errors. - Location ret = token->location(); - int nest = 0; - while (!token->is_eof()) - { - if (token->is_op(OPERATOR_LCURLY)) - ++nest; - else if (token->is_op(OPERATOR_RCURLY)) - { - --nest; - if (nest < 0) - { - this->advance_token(); - break; - } - } - token = this->advance_token(); - ret = token->location(); - } - return ret; - } - } - - Location ret = token->location(); - this->advance_token(); - return ret; -} - -// InterfaceType = "interface" "{" [ MethodSpecList ] "}" . -// MethodSpecList = MethodSpec { ";" MethodSpec } [ ";" ] . - -Type* -Parse::interface_type() -{ - go_assert(this->peek_token()->is_keyword(KEYWORD_INTERFACE)); - Location location = this->location(); - - if (!this->advance_token()->is_op(OPERATOR_LCURLY)) - { - Location token_loc = this->location(); - if (this->peek_token()->is_op(OPERATOR_SEMICOLON) - && this->advance_token()->is_op(OPERATOR_LCURLY)) - error_at(token_loc, "unexpected semicolon or newline before %<{%>"); - else - { - error_at(this->location(), "expected %<{%>"); - return Type::make_error_type(); - } - } - this->advance_token(); - - Typed_identifier_list* methods = new Typed_identifier_list(); - if (!this->peek_token()->is_op(OPERATOR_RCURLY)) - { - this->method_spec(methods); - while (this->peek_token()->is_op(OPERATOR_SEMICOLON)) - { - if (this->advance_token()->is_op(OPERATOR_RCURLY)) - break; - this->method_spec(methods); - } - if (!this->peek_token()->is_op(OPERATOR_RCURLY)) - { - error_at(this->location(), "expected %<}%>"); - while (!this->advance_token()->is_op(OPERATOR_RCURLY)) - { - if (this->peek_token()->is_eof()) - return Type::make_error_type(); - } - } - } - this->advance_token(); - - if (methods->empty()) - { - delete methods; - methods = NULL; - } - - Interface_type* ret = Type::make_interface_type(methods, location); - this->gogo_->record_interface_type(ret); - return ret; -} - -// MethodSpec = MethodName Signature | InterfaceTypeName . -// MethodName = identifier . -// InterfaceTypeName = TypeName . - -void -Parse::method_spec(Typed_identifier_list* methods) -{ - const Token* token = this->peek_token(); - if (!token->is_identifier()) - { - error_at(this->location(), "expected identifier"); - return; - } - - std::string name = token->identifier(); - bool is_exported = token->is_identifier_exported(); - Location location = token->location(); - - if (this->advance_token()->is_op(OPERATOR_LPAREN)) - { - // This is a MethodName. - name = this->gogo_->pack_hidden_name(name, is_exported); - Type* type = this->signature(NULL, location); - if (type == NULL) - return; - methods->push_back(Typed_identifier(name, type, location)); - } - else - { - this->unget_token(Token::make_identifier_token(name, is_exported, - location)); - Type* type = this->type_name(false); - if (type->is_error_type() - || (!this->peek_token()->is_op(OPERATOR_SEMICOLON) - && !this->peek_token()->is_op(OPERATOR_RCURLY))) - { - if (this->peek_token()->is_op(OPERATOR_COMMA)) - error_at(this->location(), - "name list not allowed in interface type"); - else - error_at(location, "expected signature or type name"); - this->gogo_->mark_locals_used(); - token = this->peek_token(); - while (!token->is_eof() - && !token->is_op(OPERATOR_SEMICOLON) - && !token->is_op(OPERATOR_RCURLY)) - token = this->advance_token(); - return; - } - // This must be an interface type, but we can't check that now. - // We check it and pull out the methods in - // Interface_type::do_verify. - methods->push_back(Typed_identifier("", type, location)); - } -} - -// Declaration = ConstDecl | TypeDecl | VarDecl | FunctionDecl | MethodDecl . - -void -Parse::declaration() -{ - const Token* token = this->peek_token(); - - bool saw_nointerface = this->lex_->get_and_clear_nointerface(); - if (saw_nointerface && !token->is_keyword(KEYWORD_FUNC)) - warning_at(token->location(), 0, - "ignoring magic //go:nointerface comment before non-method"); - - if (token->is_keyword(KEYWORD_CONST)) - this->const_decl(); - else if (token->is_keyword(KEYWORD_TYPE)) - this->type_decl(); - else if (token->is_keyword(KEYWORD_VAR)) - this->var_decl(); - else if (token->is_keyword(KEYWORD_FUNC)) - this->function_decl(saw_nointerface); - else - { - error_at(this->location(), "expected declaration"); - this->advance_token(); - } -} - -bool -Parse::declaration_may_start_here() -{ - const Token* token = this->peek_token(); - return (token->is_keyword(KEYWORD_CONST) - || token->is_keyword(KEYWORD_TYPE) - || token->is_keyword(KEYWORD_VAR) - || token->is_keyword(KEYWORD_FUNC)); -} - -// Decl<P> = P | "(" [ List<P> ] ")" . - -void -Parse::decl(void (Parse::*pfn)(void*), void* varg) -{ - if (this->peek_token()->is_eof()) - { - if (!saw_errors()) - error_at(this->location(), "unexpected end of file"); - return; - } - - if (!this->peek_token()->is_op(OPERATOR_LPAREN)) - (this->*pfn)(varg); - else - { - if (!this->advance_token()->is_op(OPERATOR_RPAREN)) - { - this->list(pfn, varg, true); - if (!this->peek_token()->is_op(OPERATOR_RPAREN)) - { - error_at(this->location(), "missing %<)%>"); - while (!this->advance_token()->is_op(OPERATOR_RPAREN)) - { - if (this->peek_token()->is_eof()) - return; - } - } - } - this->advance_token(); - } -} - -// List<P> = P { ";" P } [ ";" ] . - -// In order to pick up the trailing semicolon we need to know what -// might follow. This is either a '}' or a ')'. - -void -Parse::list(void (Parse::*pfn)(void*), void* varg, bool follow_is_paren) -{ - (this->*pfn)(varg); - Operator follow = follow_is_paren ? OPERATOR_RPAREN : OPERATOR_RCURLY; - while (this->peek_token()->is_op(OPERATOR_SEMICOLON) - || this->peek_token()->is_op(OPERATOR_COMMA)) - { - if (this->peek_token()->is_op(OPERATOR_COMMA)) - error_at(this->location(), "unexpected comma"); - if (this->advance_token()->is_op(follow)) - break; - (this->*pfn)(varg); - } -} - -// ConstDecl = "const" ( ConstSpec | "(" { ConstSpec ";" } ")" ) . - -void -Parse::const_decl() -{ - go_assert(this->peek_token()->is_keyword(KEYWORD_CONST)); - this->advance_token(); - this->reset_iota(); - - Type* last_type = NULL; - Expression_list* last_expr_list = NULL; - - if (!this->peek_token()->is_op(OPERATOR_LPAREN)) - this->const_spec(&last_type, &last_expr_list); - else - { - this->advance_token(); - while (!this->peek_token()->is_op(OPERATOR_RPAREN)) - { - this->const_spec(&last_type, &last_expr_list); - if (this->peek_token()->is_op(OPERATOR_SEMICOLON)) - this->advance_token(); - else if (!this->peek_token()->is_op(OPERATOR_RPAREN)) - { - error_at(this->location(), "expected %<;%> or %<)%> or newline"); - if (!this->skip_past_error(OPERATOR_RPAREN)) - return; - } - } - this->advance_token(); - } - - if (last_expr_list != NULL) - delete last_expr_list; -} - -// ConstSpec = IdentifierList [ [ CompleteType ] "=" ExpressionList ] . - -void -Parse::const_spec(Type** last_type, Expression_list** last_expr_list) -{ - Typed_identifier_list til; - this->identifier_list(&til); - - Type* type = NULL; - if (this->type_may_start_here()) - { - type = this->type(); - *last_type = NULL; - *last_expr_list = NULL; - } - - Expression_list *expr_list; - if (!this->peek_token()->is_op(OPERATOR_EQ)) - { - if (*last_expr_list == NULL) - { - error_at(this->location(), "expected %<=%>"); - return; - } - type = *last_type; - expr_list = new Expression_list; - for (Expression_list::const_iterator p = (*last_expr_list)->begin(); - p != (*last_expr_list)->end(); - ++p) - expr_list->push_back((*p)->copy()); - } - else - { - this->advance_token(); - expr_list = this->expression_list(NULL, false, true); - *last_type = type; - if (*last_expr_list != NULL) - delete *last_expr_list; - *last_expr_list = expr_list; - } - - Expression_list::const_iterator pe = expr_list->begin(); - for (Typed_identifier_list::iterator pi = til.begin(); - pi != til.end(); - ++pi, ++pe) - { - if (pe == expr_list->end()) - { - error_at(this->location(), "not enough initializers"); - return; - } - if (type != NULL) - pi->set_type(type); - - if (!Gogo::is_sink_name(pi->name())) - this->gogo_->add_constant(*pi, *pe, this->iota_value()); - } - if (pe != expr_list->end()) - error_at(this->location(), "too many initializers"); - - this->increment_iota(); - - return; -} - -// TypeDecl = "type" Decl<TypeSpec> . - -void -Parse::type_decl() -{ - go_assert(this->peek_token()->is_keyword(KEYWORD_TYPE)); - this->advance_token(); - this->decl(&Parse::type_spec, NULL); -} - -// TypeSpec = identifier Type . - -void -Parse::type_spec(void*) -{ - const Token* token = this->peek_token(); - if (!token->is_identifier()) - { - error_at(this->location(), "expected identifier"); - return; - } - std::string name = token->identifier(); - bool is_exported = token->is_identifier_exported(); - Location location = token->location(); - token = this->advance_token(); - - // The scope of the type name starts at the point where the - // identifier appears in the source code. We implement this by - // declaring the type before we read the type definition. - Named_object* named_type = NULL; - if (name != "_") - { - name = this->gogo_->pack_hidden_name(name, is_exported); - named_type = this->gogo_->declare_type(name, location); - } - - Type* type; - if (!this->peek_token()->is_op(OPERATOR_SEMICOLON)) - type = this->type(); - else - { - error_at(this->location(), - "unexpected semicolon or newline in type declaration"); - type = Type::make_error_type(); - this->advance_token(); - } - - if (type->is_error_type()) - { - this->gogo_->mark_locals_used(); - while (!this->peek_token()->is_op(OPERATOR_SEMICOLON) - && !this->peek_token()->is_eof()) - this->advance_token(); - } - - if (name != "_") - { - if (named_type->is_type_declaration()) - { - Type* ftype = type->forwarded(); - if (ftype->forward_declaration_type() != NULL - && (ftype->forward_declaration_type()->named_object() - == named_type)) - { - error_at(location, "invalid recursive type"); - type = Type::make_error_type(); - } - - this->gogo_->define_type(named_type, - Type::make_named_type(named_type, type, - location)); - go_assert(named_type->package() == NULL); - } - else - { - // This will probably give a redefinition error. - this->gogo_->add_type(name, type, location); - } - } -} - -// VarDecl = "var" Decl<VarSpec> . - -void -Parse::var_decl() -{ - go_assert(this->peek_token()->is_keyword(KEYWORD_VAR)); - this->advance_token(); - this->decl(&Parse::var_spec, NULL); -} - -// VarSpec = IdentifierList -// ( CompleteType [ "=" ExpressionList ] | "=" ExpressionList ) . - -void -Parse::var_spec(void*) -{ - // Get the variable names. - Typed_identifier_list til; - this->identifier_list(&til); - - Location location = this->location(); - - Type* type = NULL; - Expression_list* init = NULL; - if (!this->peek_token()->is_op(OPERATOR_EQ)) - { - type = this->type(); - if (type->is_error_type()) - { - this->gogo_->mark_locals_used(); - while (!this->peek_token()->is_op(OPERATOR_EQ) - && !this->peek_token()->is_op(OPERATOR_SEMICOLON) - && !this->peek_token()->is_eof()) - this->advance_token(); - } - if (this->peek_token()->is_op(OPERATOR_EQ)) - { - this->advance_token(); - init = this->expression_list(NULL, false, true); - } - } - else - { - this->advance_token(); - init = this->expression_list(NULL, false, true); - } - - this->init_vars(&til, type, init, false, location); - - if (init != NULL) - delete init; -} - -// Create variables. TIL is a list of variable names. If TYPE is not -// NULL, it is the type of all the variables. If INIT is not NULL, it -// is an initializer list for the variables. - -void -Parse::init_vars(const Typed_identifier_list* til, Type* type, - Expression_list* init, bool is_coloneq, - Location location) -{ - // Check for an initialization which can yield multiple values. - if (init != NULL && init->size() == 1 && til->size() > 1) - { - if (this->init_vars_from_call(til, type, *init->begin(), is_coloneq, - location)) - return; - if (this->init_vars_from_map(til, type, *init->begin(), is_coloneq, - location)) - return; - if (this->init_vars_from_receive(til, type, *init->begin(), is_coloneq, - location)) - return; - if (this->init_vars_from_type_guard(til, type, *init->begin(), - is_coloneq, location)) - return; - } - - if (init != NULL && init->size() != til->size()) - { - if (init->empty() || !init->front()->is_error_expression()) - error_at(location, "wrong number of initializations"); - init = NULL; - if (type == NULL) - type = Type::make_error_type(); - } - - // Note that INIT was already parsed with the old name bindings, so - // we don't have to worry that it will accidentally refer to the - // newly declared variables. But we do have to worry about a mix of - // newly declared variables and old variables if the old variables - // appear in the initializations. - - Expression_list::const_iterator pexpr; - if (init != NULL) - pexpr = init->begin(); - bool any_new = false; - Expression_list* vars = new Expression_list(); - Expression_list* vals = new Expression_list(); - for (Typed_identifier_list::const_iterator p = til->begin(); - p != til->end(); - ++p) - { - if (init != NULL) - go_assert(pexpr != init->end()); - this->init_var(*p, type, init == NULL ? NULL : *pexpr, is_coloneq, - false, &any_new, vars, vals); - if (init != NULL) - ++pexpr; - } - if (init != NULL) - go_assert(pexpr == init->end()); - if (is_coloneq && !any_new) - error_at(location, "variables redeclared but no variable is new"); - this->finish_init_vars(vars, vals, location); -} - -// See if we need to initialize a list of variables from a function -// call. This returns true if we have set up the variables and the -// initialization. - -bool -Parse::init_vars_from_call(const Typed_identifier_list* vars, Type* type, - Expression* expr, bool is_coloneq, - Location location) -{ - Call_expression* call = expr->call_expression(); - if (call == NULL) - return false; - - // This is a function call. We can't check here whether it returns - // the right number of values, but it might. Declare the variables, - // and then assign the results of the call to them. - - Named_object* first_var = NULL; - unsigned int index = 0; - bool any_new = false; - Expression_list* ivars = new Expression_list(); - Expression_list* ivals = new Expression_list(); - for (Typed_identifier_list::const_iterator pv = vars->begin(); - pv != vars->end(); - ++pv, ++index) - { - Expression* init = Expression::make_call_result(call, index); - Named_object* no = this->init_var(*pv, type, init, is_coloneq, false, - &any_new, ivars, ivals); - - if (this->gogo_->in_global_scope() && no->is_variable()) - { - if (first_var == NULL) - first_var = no; - else - { - // The subsequent vars have an implicit dependency on - // the first one, so that everything gets initialized in - // the right order and so that we detect cycles - // correctly. - this->gogo_->record_var_depends_on(no->var_value(), first_var); - } - } - } - - if (is_coloneq && !any_new) - error_at(location, "variables redeclared but no variable is new"); - - this->finish_init_vars(ivars, ivals, location); - - return true; -} - -// See if we need to initialize a pair of values from a map index -// expression. This returns true if we have set up the variables and -// the initialization. - -bool -Parse::init_vars_from_map(const Typed_identifier_list* vars, Type* type, - Expression* expr, bool is_coloneq, - Location location) -{ - Index_expression* index = expr->index_expression(); - if (index == NULL) - return false; - if (vars->size() != 2) - return false; - - // This is an index which is being assigned to two variables. It - // must be a map index. Declare the variables, and then assign the - // results of the map index. - bool any_new = false; - Typed_identifier_list::const_iterator p = vars->begin(); - Expression* init = type == NULL ? index : NULL; - Named_object* val_no = this->init_var(*p, type, init, is_coloneq, - type == NULL, &any_new, NULL, NULL); - if (type == NULL && any_new && val_no->is_variable()) - val_no->var_value()->set_type_from_init_tuple(); - Expression* val_var = Expression::make_var_reference(val_no, location); - - ++p; - Type* var_type = type; - if (var_type == NULL) - var_type = Type::lookup_bool_type(); - Named_object* no = this->init_var(*p, var_type, NULL, is_coloneq, false, - &any_new, NULL, NULL); - Expression* present_var = Expression::make_var_reference(no, location); - - if (is_coloneq && !any_new) - error_at(location, "variables redeclared but no variable is new"); - - Statement* s = Statement::make_tuple_map_assignment(val_var, present_var, - index, location); - - if (!this->gogo_->in_global_scope()) - this->gogo_->add_statement(s); - else if (!val_no->is_sink()) - { - if (val_no->is_variable()) - val_no->var_value()->add_preinit_statement(this->gogo_, s); - } - else if (!no->is_sink()) - { - if (no->is_variable()) - no->var_value()->add_preinit_statement(this->gogo_, s); - } - else - { - // Execute the map index expression just so that we can fail if - // the map is nil. - Named_object* dummy = this->create_dummy_global(Type::lookup_bool_type(), - NULL, location); - dummy->var_value()->add_preinit_statement(this->gogo_, s); - } - - return true; -} - -// See if we need to initialize a pair of values from a receive -// expression. This returns true if we have set up the variables and -// the initialization. - -bool -Parse::init_vars_from_receive(const Typed_identifier_list* vars, Type* type, - Expression* expr, bool is_coloneq, - Location location) -{ - Receive_expression* receive = expr->receive_expression(); - if (receive == NULL) - return false; - if (vars->size() != 2) - return false; - - // This is a receive expression which is being assigned to two - // variables. Declare the variables, and then assign the results of - // the receive. - bool any_new = false; - Typed_identifier_list::const_iterator p = vars->begin(); - Expression* init = type == NULL ? receive : NULL; - Named_object* val_no = this->init_var(*p, type, init, is_coloneq, - type == NULL, &any_new, NULL, NULL); - if (type == NULL && any_new && val_no->is_variable()) - val_no->var_value()->set_type_from_init_tuple(); - Expression* val_var = Expression::make_var_reference(val_no, location); - - ++p; - Type* var_type = type; - if (var_type == NULL) - var_type = Type::lookup_bool_type(); - Named_object* no = this->init_var(*p, var_type, NULL, is_coloneq, false, - &any_new, NULL, NULL); - Expression* received_var = Expression::make_var_reference(no, location); - - if (is_coloneq && !any_new) - error_at(location, "variables redeclared but no variable is new"); - - Statement* s = Statement::make_tuple_receive_assignment(val_var, - received_var, - receive->channel(), - location); - - if (!this->gogo_->in_global_scope()) - this->gogo_->add_statement(s); - else if (!val_no->is_sink()) - { - if (val_no->is_variable()) - val_no->var_value()->add_preinit_statement(this->gogo_, s); - } - else if (!no->is_sink()) - { - if (no->is_variable()) - no->var_value()->add_preinit_statement(this->gogo_, s); - } - else - { - Named_object* dummy = this->create_dummy_global(Type::lookup_bool_type(), - NULL, location); - dummy->var_value()->add_preinit_statement(this->gogo_, s); - } - - return true; -} - -// See if we need to initialize a pair of values from a type guard -// expression. This returns true if we have set up the variables and -// the initialization. - -bool -Parse::init_vars_from_type_guard(const Typed_identifier_list* vars, - Type* type, Expression* expr, - bool is_coloneq, Location location) -{ - Type_guard_expression* type_guard = expr->type_guard_expression(); - if (type_guard == NULL) - return false; - if (vars->size() != 2) - return false; - - // This is a type guard expression which is being assigned to two - // variables. Declare the variables, and then assign the results of - // the type guard. - bool any_new = false; - Typed_identifier_list::const_iterator p = vars->begin(); - Type* var_type = type; - if (var_type == NULL) - var_type = type_guard->type(); - Named_object* val_no = this->init_var(*p, var_type, NULL, is_coloneq, false, - &any_new, NULL, NULL); - Expression* val_var = Expression::make_var_reference(val_no, location); - - ++p; - var_type = type; - if (var_type == NULL) - var_type = Type::lookup_bool_type(); - Named_object* no = this->init_var(*p, var_type, NULL, is_coloneq, false, - &any_new, NULL, NULL); - Expression* ok_var = Expression::make_var_reference(no, location); - - Expression* texpr = type_guard->expr(); - Type* t = type_guard->type(); - Statement* s = Statement::make_tuple_type_guard_assignment(val_var, ok_var, - texpr, t, - location); - - if (is_coloneq && !any_new) - error_at(location, "variables redeclared but no variable is new"); - - if (!this->gogo_->in_global_scope()) - this->gogo_->add_statement(s); - else if (!val_no->is_sink()) - { - if (val_no->is_variable()) - val_no->var_value()->add_preinit_statement(this->gogo_, s); - } - else if (!no->is_sink()) - { - if (no->is_variable()) - no->var_value()->add_preinit_statement(this->gogo_, s); - } - else - { - Named_object* dummy = this->create_dummy_global(type, NULL, location); - dummy->var_value()->add_preinit_statement(this->gogo_, s); - } - - return true; -} - -// Create a single variable. If IS_COLONEQ is true, we permit -// redeclarations in the same block, and we set *IS_NEW when we find a -// new variable which is not a redeclaration. - -Named_object* -Parse::init_var(const Typed_identifier& tid, Type* type, Expression* init, - bool is_coloneq, bool type_from_init, bool* is_new, - Expression_list* vars, Expression_list* vals) -{ - Location location = tid.location(); - - if (Gogo::is_sink_name(tid.name())) - { - if (!type_from_init && init != NULL) - { - if (this->gogo_->in_global_scope()) - return this->create_dummy_global(type, init, location); - else if (type == NULL) - this->gogo_->add_statement(Statement::make_statement(init, true)); - else - { - // With both a type and an initializer, create a dummy - // variable so that we will check whether the - // initializer can be assigned to the type. - Variable* var = new Variable(type, init, false, false, false, - location); - var->set_is_used(); - static int count; - char buf[30]; - snprintf(buf, sizeof buf, "sink$%d", count); - ++count; - return this->gogo_->add_variable(buf, var); - } - } - if (type != NULL) - this->gogo_->add_type_to_verify(type); - return this->gogo_->add_sink(); - } - - if (is_coloneq) - { - Named_object* no = this->gogo_->lookup_in_block(tid.name()); - if (no != NULL - && (no->is_variable() || no->is_result_variable())) - { - // INIT may be NULL even when IS_COLONEQ is true for cases - // like v, ok := x.(int). - if (!type_from_init && init != NULL) - { - go_assert(vars != NULL && vals != NULL); - vars->push_back(Expression::make_var_reference(no, location)); - vals->push_back(init); - } - return no; - } - } - *is_new = true; - Variable* var = new Variable(type, init, this->gogo_->in_global_scope(), - false, false, location); - Named_object* no = this->gogo_->add_variable(tid.name(), var); - if (!no->is_variable()) - { - // The name is already defined, so we just gave an error. - return this->gogo_->add_sink(); - } - return no; -} - -// Create a dummy global variable to force an initializer to be run in -// the right place. This is used when a sink variable is initialized -// at global scope. - -Named_object* -Parse::create_dummy_global(Type* type, Expression* init, - Location location) -{ - if (type == NULL && init == NULL) - type = Type::lookup_bool_type(); - Variable* var = new Variable(type, init, true, false, false, location); - static int count; - char buf[30]; - snprintf(buf, sizeof buf, "_.%d", count); - ++count; - return this->gogo_->add_variable(buf, var); -} - -// Finish the variable initialization by executing any assignments to -// existing variables when using :=. These must be done as a tuple -// assignment in case of something like n, a, b := 1, b, a. - -void -Parse::finish_init_vars(Expression_list* vars, Expression_list* vals, - Location location) -{ - if (vars->empty()) - { - delete vars; - delete vals; - } - else if (vars->size() == 1) - { - go_assert(!this->gogo_->in_global_scope()); - this->gogo_->add_statement(Statement::make_assignment(vars->front(), - vals->front(), - location)); - delete vars; - delete vals; - } - else - { - go_assert(!this->gogo_->in_global_scope()); - this->gogo_->add_statement(Statement::make_tuple_assignment(vars, vals, - location)); - } -} - -// SimpleVarDecl = identifier ":=" Expression . - -// We've already seen the identifier. - -// FIXME: We also have to implement -// IdentifierList ":=" ExpressionList -// In order to support both "a, b := 1, 0" and "a, b = 1, 0" we accept -// tuple assignments here as well. - -// If MAY_BE_COMPOSITE_LIT is true, the expression on the right hand -// side may be a composite literal. - -// If P_RANGE_CLAUSE is not NULL, then this will recognize a -// RangeClause. - -// If P_TYPE_SWITCH is not NULL, this will recognize a type switch -// guard (var := expr.("type") using the literal keyword "type"). - -void -Parse::simple_var_decl_or_assignment(const std::string& name, - Location location, - bool may_be_composite_lit, - Range_clause* p_range_clause, - Type_switch* p_type_switch) -{ - Typed_identifier_list til; - til.push_back(Typed_identifier(name, NULL, location)); - - // We've seen one identifier. If we see a comma now, this could be - // "a, *p = 1, 2". - if (this->peek_token()->is_op(OPERATOR_COMMA)) - { - go_assert(p_type_switch == NULL); - while (true) - { - const Token* token = this->advance_token(); - if (!token->is_identifier()) - break; - - std::string id = token->identifier(); - bool is_id_exported = token->is_identifier_exported(); - Location id_location = token->location(); - - token = this->advance_token(); - if (!token->is_op(OPERATOR_COMMA)) - { - if (token->is_op(OPERATOR_COLONEQ)) - { - id = this->gogo_->pack_hidden_name(id, is_id_exported); - til.push_back(Typed_identifier(id, NULL, location)); - } - else - this->unget_token(Token::make_identifier_token(id, - is_id_exported, - id_location)); - break; - } - - id = this->gogo_->pack_hidden_name(id, is_id_exported); - til.push_back(Typed_identifier(id, NULL, location)); - } - - // We have a comma separated list of identifiers in TIL. If the - // next token is COLONEQ, then this is a simple var decl, and we - // have the complete list of identifiers. If the next token is - // not COLONEQ, then the only valid parse is a tuple assignment. - // The list of identifiers we have so far is really a list of - // expressions. There are more expressions following. - - if (!this->peek_token()->is_op(OPERATOR_COLONEQ)) - { - Expression_list* exprs = new Expression_list; - for (Typed_identifier_list::const_iterator p = til.begin(); - p != til.end(); - ++p) - exprs->push_back(this->id_to_expression(p->name(), - p->location())); - - Expression_list* more_exprs = - this->expression_list(NULL, true, may_be_composite_lit); - for (Expression_list::const_iterator p = more_exprs->begin(); - p != more_exprs->end(); - ++p) - exprs->push_back(*p); - delete more_exprs; - - this->tuple_assignment(exprs, may_be_composite_lit, p_range_clause); - return; - } - } - - go_assert(this->peek_token()->is_op(OPERATOR_COLONEQ)); - const Token* token = this->advance_token(); - - if (p_range_clause != NULL && token->is_keyword(KEYWORD_RANGE)) - { - this->range_clause_decl(&til, p_range_clause); - return; - } - - Expression_list* init; - if (p_type_switch == NULL) - init = this->expression_list(NULL, false, may_be_composite_lit); - else - { - bool is_type_switch = false; - Expression* expr = this->expression(PRECEDENCE_NORMAL, false, - may_be_composite_lit, - &is_type_switch, NULL); - if (is_type_switch) - { - p_type_switch->found = true; - p_type_switch->name = name; - p_type_switch->location = location; - p_type_switch->expr = expr; - return; - } - - if (!this->peek_token()->is_op(OPERATOR_COMMA)) - { - init = new Expression_list(); - init->push_back(expr); - } - else - { - this->advance_token(); - init = this->expression_list(expr, false, may_be_composite_lit); - } - } - - this->init_vars(&til, NULL, init, true, location); -} - -// FunctionDecl = "func" identifier Signature [ Block ] . -// MethodDecl = "func" Receiver identifier Signature [ Block ] . - -// Deprecated gcc extension: -// FunctionDecl = "func" identifier Signature -// __asm__ "(" string_lit ")" . -// This extension means a function whose real name is the identifier -// inside the asm. This extension will be removed at some future -// date. It has been replaced with //extern comments. - -// SAW_NOINTERFACE is true if we saw a magic //go:nointerface comment, -// which means that we omit the method from the type descriptor. - -void -Parse::function_decl(bool saw_nointerface) -{ - go_assert(this->peek_token()->is_keyword(KEYWORD_FUNC)); - Location location = this->location(); - std::string extern_name = this->lex_->extern_name(); - const Token* token = this->advance_token(); - - Typed_identifier* rec = NULL; - if (token->is_op(OPERATOR_LPAREN)) - { - rec = this->receiver(); - token = this->peek_token(); - } - else if (saw_nointerface) - { - warning_at(location, 0, - "ignoring magic //go:nointerface comment before non-method"); - saw_nointerface = false; - } - - if (!token->is_identifier()) - { - error_at(this->location(), "expected function name"); - return; - } - - std::string name = - this->gogo_->pack_hidden_name(token->identifier(), - token->is_identifier_exported()); - - this->advance_token(); - - Function_type* fntype = this->signature(rec, this->location()); - - Named_object* named_object = NULL; - - if (this->peek_token()->is_keyword(KEYWORD_ASM)) - { - if (!this->advance_token()->is_op(OPERATOR_LPAREN)) - { - error_at(this->location(), "expected %<(%>"); - return; - } - token = this->advance_token(); - if (!token->is_string()) - { - error_at(this->location(), "expected string"); - return; - } - std::string asm_name = token->string_value(); - if (!this->advance_token()->is_op(OPERATOR_RPAREN)) - { - error_at(this->location(), "expected %<)%>"); - return; - } - this->advance_token(); - if (!Gogo::is_sink_name(name)) - { - named_object = this->gogo_->declare_function(name, fntype, location); - if (named_object->is_function_declaration()) - named_object->func_declaration_value()->set_asm_name(asm_name); - } - } - - // Check for the easy error of a newline before the opening brace. - if (this->peek_token()->is_op(OPERATOR_SEMICOLON)) - { - Location semi_loc = this->location(); - if (this->advance_token()->is_op(OPERATOR_LCURLY)) - error_at(this->location(), - "unexpected semicolon or newline before %<{%>"); - else - this->unget_token(Token::make_operator_token(OPERATOR_SEMICOLON, - semi_loc)); - } - - if (!this->peek_token()->is_op(OPERATOR_LCURLY)) - { - if (named_object == NULL && !Gogo::is_sink_name(name)) - { - if (fntype == NULL) - this->gogo_->add_erroneous_name(name); - else - { - named_object = this->gogo_->declare_function(name, fntype, - location); - if (!extern_name.empty() - && named_object->is_function_declaration()) - { - Function_declaration* fd = - named_object->func_declaration_value(); - fd->set_asm_name(extern_name); - } - } - } - - if (saw_nointerface) - warning_at(location, 0, - ("ignoring magic //go:nointerface comment " - "before declaration")); - } - else - { - bool hold_is_erroneous_function = this->is_erroneous_function_; - if (fntype == NULL) - { - fntype = Type::make_function_type(NULL, NULL, NULL, location); - this->is_erroneous_function_ = true; - if (!Gogo::is_sink_name(name)) - this->gogo_->add_erroneous_name(name); - name = this->gogo_->pack_hidden_name("_", false); - } - named_object = this->gogo_->start_function(name, fntype, true, location); - Location end_loc = this->block(); - this->gogo_->finish_function(end_loc); - if (saw_nointerface - && !this->is_erroneous_function_ - && named_object->is_function()) - named_object->func_value()->set_nointerface(); - this->is_erroneous_function_ = hold_is_erroneous_function; - } -} - -// Receiver = "(" [ identifier ] [ "*" ] BaseTypeName ")" . -// BaseTypeName = identifier . - -Typed_identifier* -Parse::receiver() -{ - go_assert(this->peek_token()->is_op(OPERATOR_LPAREN)); - - std::string name; - const Token* token = this->advance_token(); - Location location = token->location(); - if (!token->is_op(OPERATOR_MULT)) - { - if (!token->is_identifier()) - { - error_at(this->location(), "method has no receiver"); - this->gogo_->mark_locals_used(); - while (!token->is_eof() && !token->is_op(OPERATOR_RPAREN)) - token = this->advance_token(); - if (!token->is_eof()) - this->advance_token(); - return NULL; - } - name = token->identifier(); - bool is_exported = token->is_identifier_exported(); - token = this->advance_token(); - if (!token->is_op(OPERATOR_DOT) && !token->is_op(OPERATOR_RPAREN)) - { - // An identifier followed by something other than a dot or a - // right parenthesis must be a receiver name followed by a - // type. - name = this->gogo_->pack_hidden_name(name, is_exported); - } - else - { - // This must be a type name. - this->unget_token(Token::make_identifier_token(name, is_exported, - location)); - token = this->peek_token(); - name.clear(); - } - } - - // Here the receiver name is in NAME (it is empty if the receiver is - // unnamed) and TOKEN is the first token in the type. - - bool is_pointer = false; - if (token->is_op(OPERATOR_MULT)) - { - is_pointer = true; - token = this->advance_token(); - } - - if (!token->is_identifier()) - { - error_at(this->location(), "expected receiver name or type"); - this->gogo_->mark_locals_used(); - int c = token->is_op(OPERATOR_LPAREN) ? 1 : 0; - while (!token->is_eof()) - { - token = this->advance_token(); - if (token->is_op(OPERATOR_LPAREN)) - ++c; - else if (token->is_op(OPERATOR_RPAREN)) - { - if (c == 0) - break; - --c; - } - } - if (!token->is_eof()) - this->advance_token(); - return NULL; - } - - Type* type = this->type_name(true); - - if (is_pointer && !type->is_error_type()) - type = Type::make_pointer_type(type); - - if (this->peek_token()->is_op(OPERATOR_RPAREN)) - this->advance_token(); - else - { - if (this->peek_token()->is_op(OPERATOR_COMMA)) - error_at(this->location(), "method has multiple receivers"); - else - error_at(this->location(), "expected %<)%>"); - this->gogo_->mark_locals_used(); - while (!token->is_eof() && !token->is_op(OPERATOR_RPAREN)) - token = this->advance_token(); - if (!token->is_eof()) - this->advance_token(); - return NULL; - } - - return new Typed_identifier(name, type, location); -} - -// Operand = Literal | QualifiedIdent | MethodExpr | "(" Expression ")" . -// Literal = BasicLit | CompositeLit | FunctionLit . -// BasicLit = int_lit | float_lit | imaginary_lit | char_lit | string_lit . - -// If MAY_BE_SINK is true, this operand may be "_". - -// If IS_PARENTHESIZED is not NULL, *IS_PARENTHESIZED is set to true -// if the entire expression is in parentheses. - -Expression* -Parse::operand(bool may_be_sink, bool* is_parenthesized) -{ - const Token* token = this->peek_token(); - Expression* ret; - switch (token->classification()) - { - case Token::TOKEN_IDENTIFIER: - { - Location location = token->location(); - std::string id = token->identifier(); - bool is_exported = token->is_identifier_exported(); - std::string packed = this->gogo_->pack_hidden_name(id, is_exported); - - Named_object* in_function; - Named_object* named_object = this->gogo_->lookup(packed, &in_function); - - Package* package = NULL; - if (named_object != NULL && named_object->is_package()) - { - if (!this->advance_token()->is_op(OPERATOR_DOT) - || !this->advance_token()->is_identifier()) - { - error_at(location, "unexpected reference to package"); - return Expression::make_error(location); - } - package = named_object->package_value(); - package->set_used(); - id = this->peek_token()->identifier(); - is_exported = this->peek_token()->is_identifier_exported(); - packed = this->gogo_->pack_hidden_name(id, is_exported); - named_object = package->lookup(packed); - location = this->location(); - go_assert(in_function == NULL); - } - - this->advance_token(); - - if (named_object != NULL - && named_object->is_type() - && !named_object->type_value()->is_visible()) - { - go_assert(package != NULL); - error_at(location, "invalid reference to hidden type %<%s.%s%>", - Gogo::message_name(package->package_name()).c_str(), - Gogo::message_name(id).c_str()); - return Expression::make_error(location); - } - - - if (named_object == NULL) - { - if (package != NULL) - { - std::string n1 = Gogo::message_name(package->package_name()); - std::string n2 = Gogo::message_name(id); - if (!is_exported) - error_at(location, - ("invalid reference to unexported identifier " - "%<%s.%s%>"), - n1.c_str(), n2.c_str()); - else - error_at(location, - "reference to undefined identifier %<%s.%s%>", - n1.c_str(), n2.c_str()); - return Expression::make_error(location); - } - - named_object = this->gogo_->add_unknown_name(packed, location); - } - - if (in_function != NULL - && in_function != this->gogo_->current_function() - && (named_object->is_variable() - || named_object->is_result_variable())) - return this->enclosing_var_reference(in_function, named_object, - location); - - switch (named_object->classification()) - { - case Named_object::NAMED_OBJECT_CONST: - return Expression::make_const_reference(named_object, location); - case Named_object::NAMED_OBJECT_TYPE: - return Expression::make_type(named_object->type_value(), location); - case Named_object::NAMED_OBJECT_TYPE_DECLARATION: - { - Type* t = Type::make_forward_declaration(named_object); - return Expression::make_type(t, location); - } - case Named_object::NAMED_OBJECT_VAR: - case Named_object::NAMED_OBJECT_RESULT_VAR: - this->mark_var_used(named_object); - return Expression::make_var_reference(named_object, location); - case Named_object::NAMED_OBJECT_SINK: - if (may_be_sink) - return Expression::make_sink(location); - else - { - error_at(location, "cannot use _ as value"); - return Expression::make_error(location); - } - case Named_object::NAMED_OBJECT_FUNC: - case Named_object::NAMED_OBJECT_FUNC_DECLARATION: - return Expression::make_func_reference(named_object, NULL, - location); - case Named_object::NAMED_OBJECT_UNKNOWN: - { - Unknown_expression* ue = - Expression::make_unknown_reference(named_object, location); - if (this->is_erroneous_function_) - ue->set_no_error_message(); - return ue; - } - case Named_object::NAMED_OBJECT_ERRONEOUS: - return Expression::make_error(location); - default: - go_unreachable(); - } - } - go_unreachable(); - - case Token::TOKEN_STRING: - ret = Expression::make_string(token->string_value(), token->location()); - this->advance_token(); - return ret; - - case Token::TOKEN_CHARACTER: - ret = Expression::make_character(token->character_value(), NULL, - token->location()); - this->advance_token(); - return ret; - - case Token::TOKEN_INTEGER: - ret = Expression::make_integer(token->integer_value(), NULL, - token->location()); - this->advance_token(); - return ret; - - case Token::TOKEN_FLOAT: - ret = Expression::make_float(token->float_value(), NULL, - token->location()); - this->advance_token(); - return ret; - - case Token::TOKEN_IMAGINARY: - { - mpfr_t zero; - mpfr_init_set_ui(zero, 0, GMP_RNDN); - ret = Expression::make_complex(&zero, token->imaginary_value(), - NULL, token->location()); - mpfr_clear(zero); - this->advance_token(); - return ret; - } - - case Token::TOKEN_KEYWORD: - switch (token->keyword()) - { - case KEYWORD_FUNC: - return this->function_lit(); - case KEYWORD_CHAN: - case KEYWORD_INTERFACE: - case KEYWORD_MAP: - case KEYWORD_STRUCT: - { - Location location = token->location(); - return Expression::make_type(this->type(), location); - } - default: - break; - } - break; - - case Token::TOKEN_OPERATOR: - if (token->is_op(OPERATOR_LPAREN)) - { - this->advance_token(); - ret = this->expression(PRECEDENCE_NORMAL, may_be_sink, true, NULL, - NULL); - if (!this->peek_token()->is_op(OPERATOR_RPAREN)) - error_at(this->location(), "missing %<)%>"); - else - this->advance_token(); - if (is_parenthesized != NULL) - *is_parenthesized = true; - return ret; - } - else if (token->is_op(OPERATOR_LSQUARE)) - { - // Here we call array_type directly, as this is the only - // case where an ellipsis is permitted for an array type. - Location location = token->location(); - return Expression::make_type(this->array_type(true), location); - } - break; - - default: - break; - } - - error_at(this->location(), "expected operand"); - return Expression::make_error(this->location()); -} - -// Handle a reference to a variable in an enclosing function. We add -// it to a list of such variables. We return a reference to a field -// in a struct which will be passed on the static chain when calling -// the current function. - -Expression* -Parse::enclosing_var_reference(Named_object* in_function, Named_object* var, - Location location) -{ - go_assert(var->is_variable() || var->is_result_variable()); - - this->mark_var_used(var); - - Named_object* this_function = this->gogo_->current_function(); - Named_object* closure = this_function->func_value()->closure_var(); - - Enclosing_var ev(var, in_function, this->enclosing_vars_.size()); - std::pair<Enclosing_vars::iterator, bool> ins = - this->enclosing_vars_.insert(ev); - if (ins.second) - { - // This is a variable we have not seen before. Add a new field - // to the closure type. - this_function->func_value()->add_closure_field(var, location); - } - - Expression* closure_ref = Expression::make_var_reference(closure, - location); - closure_ref = Expression::make_unary(OPERATOR_MULT, closure_ref, location); - - // The closure structure holds pointers to the variables, so we need - // to introduce an indirection. - Expression* e = Expression::make_field_reference(closure_ref, - ins.first->index(), - location); - e = Expression::make_unary(OPERATOR_MULT, e, location); - return e; -} - -// CompositeLit = LiteralType LiteralValue . -// LiteralType = StructType | ArrayType | "[" "..." "]" ElementType | -// SliceType | MapType | TypeName . -// LiteralValue = "{" [ ElementList [ "," ] ] "}" . -// ElementList = Element { "," Element } . -// Element = [ Key ":" ] Value . -// Key = FieldName | ElementIndex . -// FieldName = identifier . -// ElementIndex = Expression . -// Value = Expression | LiteralValue . - -// We have already seen the type if there is one, and we are now -// looking at the LiteralValue. The case "[" "..." "]" ElementType -// will be seen here as an array type whose length is "nil". The -// DEPTH parameter is non-zero if this is an embedded composite -// literal and the type was omitted. It gives the number of steps up -// to the type which was provided. E.g., in [][]int{{1}} it will be -// 1. In [][][]int{{{1}}} it will be 2. - -Expression* -Parse::composite_lit(Type* type, int depth, Location location) -{ - go_assert(this->peek_token()->is_op(OPERATOR_LCURLY)); - this->advance_token(); - - if (this->peek_token()->is_op(OPERATOR_RCURLY)) - { - this->advance_token(); - return Expression::make_composite_literal(type, depth, false, NULL, - location); - } - - bool has_keys = false; - Expression_list* vals = new Expression_list; - while (true) - { - Expression* val; - bool is_type_omitted = false; - - const Token* token = this->peek_token(); - - if (token->is_identifier()) - { - std::string identifier = token->identifier(); - bool is_exported = token->is_identifier_exported(); - Location location = token->location(); - - if (this->advance_token()->is_op(OPERATOR_COLON)) - { - // This may be a field name. We don't know for sure--it - // could also be an expression for an array index. We - // don't want to parse it as an expression because may - // trigger various errors, e.g., if this identifier - // happens to be the name of a package. - Gogo* gogo = this->gogo_; - val = this->id_to_expression(gogo->pack_hidden_name(identifier, - is_exported), - location); - } - else - { - this->unget_token(Token::make_identifier_token(identifier, - is_exported, - location)); - val = this->expression(PRECEDENCE_NORMAL, false, true, NULL, - NULL); - } - } - else if (!token->is_op(OPERATOR_LCURLY)) - val = this->expression(PRECEDENCE_NORMAL, false, true, NULL, NULL); - else - { - // This must be a composite literal inside another composite - // literal, with the type omitted for the inner one. - val = this->composite_lit(type, depth + 1, token->location()); - is_type_omitted = true; - } - - token = this->peek_token(); - if (!token->is_op(OPERATOR_COLON)) - { - if (has_keys) - vals->push_back(NULL); - } - else - { - if (is_type_omitted && !val->is_error_expression()) - { - error_at(this->location(), "unexpected %<:%>"); - val = Expression::make_error(this->location()); - } - - this->advance_token(); - - if (!has_keys && !vals->empty()) - { - Expression_list* newvals = new Expression_list; - for (Expression_list::const_iterator p = vals->begin(); - p != vals->end(); - ++p) - { - newvals->push_back(NULL); - newvals->push_back(*p); - } - delete vals; - vals = newvals; - } - has_keys = true; - - if (val->unknown_expression() != NULL) - val->unknown_expression()->set_is_composite_literal_key(); - - vals->push_back(val); - - if (!token->is_op(OPERATOR_LCURLY)) - val = this->expression(PRECEDENCE_NORMAL, false, true, NULL, NULL); - else - { - // This must be a composite literal inside another - // composite literal, with the type omitted for the - // inner one. - val = this->composite_lit(type, depth + 1, token->location()); - } - - token = this->peek_token(); - } - - vals->push_back(val); - - if (token->is_op(OPERATOR_COMMA)) - { - if (this->advance_token()->is_op(OPERATOR_RCURLY)) - { - this->advance_token(); - break; - } - } - else if (token->is_op(OPERATOR_RCURLY)) - { - this->advance_token(); - break; - } - else - { - if (token->is_op(OPERATOR_SEMICOLON)) - error_at(this->location(), - "need trailing comma before newline in composite literal"); - else - error_at(this->location(), "expected %<,%> or %<}%>"); - - this->gogo_->mark_locals_used(); - int depth = 0; - while (!token->is_eof() - && (depth > 0 || !token->is_op(OPERATOR_RCURLY))) - { - if (token->is_op(OPERATOR_LCURLY)) - ++depth; - else if (token->is_op(OPERATOR_RCURLY)) - --depth; - token = this->advance_token(); - } - if (token->is_op(OPERATOR_RCURLY)) - this->advance_token(); - - return Expression::make_error(location); - } - } - - return Expression::make_composite_literal(type, depth, has_keys, vals, - location); -} - -// FunctionLit = "func" Signature Block . - -Expression* -Parse::function_lit() -{ - Location location = this->location(); - go_assert(this->peek_token()->is_keyword(KEYWORD_FUNC)); - this->advance_token(); - - Enclosing_vars hold_enclosing_vars; - hold_enclosing_vars.swap(this->enclosing_vars_); - - Function_type* type = this->signature(NULL, location); - bool fntype_is_error = false; - if (type == NULL) - { - type = Type::make_function_type(NULL, NULL, NULL, location); - fntype_is_error = true; - } - - // For a function literal, the next token must be a '{'. If we - // don't see that, then we may have a type expression. - if (!this->peek_token()->is_op(OPERATOR_LCURLY)) - return Expression::make_type(type, location); - - bool hold_is_erroneous_function = this->is_erroneous_function_; - if (fntype_is_error) - this->is_erroneous_function_ = true; - - Bc_stack* hold_break_stack = this->break_stack_; - Bc_stack* hold_continue_stack = this->continue_stack_; - this->break_stack_ = NULL; - this->continue_stack_ = NULL; - - Named_object* no = this->gogo_->start_function("", type, true, location); - - Location end_loc = this->block(); - - this->gogo_->finish_function(end_loc); - - if (this->break_stack_ != NULL) - delete this->break_stack_; - if (this->continue_stack_ != NULL) - delete this->continue_stack_; - this->break_stack_ = hold_break_stack; - this->continue_stack_ = hold_continue_stack; - - this->is_erroneous_function_ = hold_is_erroneous_function; - - hold_enclosing_vars.swap(this->enclosing_vars_); - - Expression* closure = this->create_closure(no, &hold_enclosing_vars, - location); - - return Expression::make_func_reference(no, closure, location); -} - -// Create a closure for the nested function FUNCTION. This is based -// on ENCLOSING_VARS, which is a list of all variables defined in -// enclosing functions and referenced from FUNCTION. A closure is the -// address of a struct which contains the addresses of all the -// referenced variables. This returns NULL if no closure is required. - -Expression* -Parse::create_closure(Named_object* function, Enclosing_vars* enclosing_vars, - Location location) -{ - if (enclosing_vars->empty()) - return NULL; - - // Get the variables in order by their field index. - - size_t enclosing_var_count = enclosing_vars->size(); - std::vector<Enclosing_var> ev(enclosing_var_count); - for (Enclosing_vars::const_iterator p = enclosing_vars->begin(); - p != enclosing_vars->end(); - ++p) - ev[p->index()] = *p; - - // Build an initializer for a composite literal of the closure's - // type. - - Named_object* enclosing_function = this->gogo_->current_function(); - Expression_list* initializer = new Expression_list; - for (size_t i = 0; i < enclosing_var_count; ++i) - { - go_assert(ev[i].index() == i); - Named_object* var = ev[i].var(); - Expression* ref; - if (ev[i].in_function() == enclosing_function) - ref = Expression::make_var_reference(var, location); - else - ref = this->enclosing_var_reference(ev[i].in_function(), var, - location); - Expression* refaddr = Expression::make_unary(OPERATOR_AND, ref, - location); - initializer->push_back(refaddr); - } - - Named_object* closure_var = function->func_value()->closure_var(); - Struct_type* st = closure_var->var_value()->type()->deref()->struct_type(); - Expression* cv = Expression::make_struct_composite_literal(st, initializer, - location); - return Expression::make_heap_composite(cv, location); -} - -// PrimaryExpr = Operand { Selector | Index | Slice | TypeGuard | Call } . - -// If MAY_BE_SINK is true, this expression may be "_". - -// If MAY_BE_COMPOSITE_LIT is true, this expression may be a composite -// literal. - -// If IS_TYPE_SWITCH is not NULL, this will recognize a type switch -// guard (var := expr.("type") using the literal keyword "type"). - -// If IS_PARENTHESIZED is not NULL, *IS_PARENTHESIZED is set to true -// if the entire expression is in parentheses. - -Expression* -Parse::primary_expr(bool may_be_sink, bool may_be_composite_lit, - bool* is_type_switch, bool* is_parenthesized) -{ - Location start_loc = this->location(); - bool operand_is_parenthesized = false; - bool whole_is_parenthesized = false; - - Expression* ret = this->operand(may_be_sink, &operand_is_parenthesized); - - whole_is_parenthesized = operand_is_parenthesized; - - // An unknown name followed by a curly brace must be a composite - // literal, and the unknown name must be a type. - if (may_be_composite_lit - && !operand_is_parenthesized - && ret->unknown_expression() != NULL - && this->peek_token()->is_op(OPERATOR_LCURLY)) - { - Named_object* no = ret->unknown_expression()->named_object(); - Type* type = Type::make_forward_declaration(no); - ret = Expression::make_type(type, ret->location()); - } - - // We handle composite literals and type casts here, as it is the - // easiest way to handle types which are in parentheses, as in - // "((uint))(1)". - if (ret->is_type_expression()) - { - if (this->peek_token()->is_op(OPERATOR_LCURLY)) - { - whole_is_parenthesized = false; - if (!may_be_composite_lit) - { - Type* t = ret->type(); - if (t->named_type() != NULL - || t->forward_declaration_type() != NULL) - error_at(start_loc, - _("parentheses required around this composite literal " - "to avoid parsing ambiguity")); - } - else if (operand_is_parenthesized) - error_at(start_loc, - "cannot parenthesize type in composite literal"); - ret = this->composite_lit(ret->type(), 0, ret->location()); - } - else if (this->peek_token()->is_op(OPERATOR_LPAREN)) - { - whole_is_parenthesized = false; - Location loc = this->location(); - this->advance_token(); - Expression* expr = this->expression(PRECEDENCE_NORMAL, false, true, - NULL, NULL); - if (this->peek_token()->is_op(OPERATOR_COMMA)) - this->advance_token(); - if (this->peek_token()->is_op(OPERATOR_ELLIPSIS)) - { - error_at(this->location(), - "invalid use of %<...%> in type conversion"); - this->advance_token(); - } - if (!this->peek_token()->is_op(OPERATOR_RPAREN)) - error_at(this->location(), "expected %<)%>"); - else - this->advance_token(); - if (expr->is_error_expression()) - ret = expr; - else - { - Type* t = ret->type(); - if (t->classification() == Type::TYPE_ARRAY - && t->array_type()->length() != NULL - && t->array_type()->length()->is_nil_expression()) - { - error_at(ret->location(), - "invalid use of %<...%> in type conversion"); - ret = Expression::make_error(loc); - } - else - ret = Expression::make_cast(t, expr, loc); - } - } - } - - while (true) - { - const Token* token = this->peek_token(); - if (token->is_op(OPERATOR_LPAREN)) - { - whole_is_parenthesized = false; - ret = this->call(this->verify_not_sink(ret)); - } - else if (token->is_op(OPERATOR_DOT)) - { - whole_is_parenthesized = false; - ret = this->selector(this->verify_not_sink(ret), is_type_switch); - if (is_type_switch != NULL && *is_type_switch) - break; - } - else if (token->is_op(OPERATOR_LSQUARE)) - { - whole_is_parenthesized = false; - ret = this->index(this->verify_not_sink(ret)); - } - else - break; - } - - if (whole_is_parenthesized && is_parenthesized != NULL) - *is_parenthesized = true; - - return ret; -} - -// Selector = "." identifier . -// TypeGuard = "." "(" QualifiedIdent ")" . - -// Note that Operand can expand to QualifiedIdent, which contains a -// ".". That is handled directly in operand when it sees a package -// name. - -// If IS_TYPE_SWITCH is not NULL, this will recognize a type switch -// guard (var := expr.("type") using the literal keyword "type"). - -Expression* -Parse::selector(Expression* left, bool* is_type_switch) -{ - go_assert(this->peek_token()->is_op(OPERATOR_DOT)); - Location location = this->location(); - - const Token* token = this->advance_token(); - if (token->is_identifier()) - { - // This could be a field in a struct, or a method in an - // interface, or a method associated with a type. We can't know - // which until we have seen all the types. - std::string name = - this->gogo_->pack_hidden_name(token->identifier(), - token->is_identifier_exported()); - if (token->identifier() == "_") - { - error_at(this->location(), "invalid use of %<_%>"); - name = this->gogo_->pack_hidden_name("blank", false); - } - this->advance_token(); - return Expression::make_selector(left, name, location); - } - else if (token->is_op(OPERATOR_LPAREN)) - { - this->advance_token(); - Type* type = NULL; - if (!this->peek_token()->is_keyword(KEYWORD_TYPE)) - type = this->type(); - else - { - if (is_type_switch != NULL) - *is_type_switch = true; - else - { - error_at(this->location(), - "use of %<.(type)%> outside type switch"); - type = Type::make_error_type(); - } - this->advance_token(); - } - if (!this->peek_token()->is_op(OPERATOR_RPAREN)) - error_at(this->location(), "missing %<)%>"); - else - this->advance_token(); - if (is_type_switch != NULL && *is_type_switch) - return left; - return Expression::make_type_guard(left, type, location); - } - else - { - error_at(this->location(), "expected identifier or %<(%>"); - return left; - } -} - -// Index = "[" Expression "]" . -// Slice = "[" Expression ":" [ Expression ] "]" . - -Expression* -Parse::index(Expression* expr) -{ - Location location = this->location(); - go_assert(this->peek_token()->is_op(OPERATOR_LSQUARE)); - this->advance_token(); - - Expression* start; - if (!this->peek_token()->is_op(OPERATOR_COLON)) - start = this->expression(PRECEDENCE_NORMAL, false, true, NULL, NULL); - else - { - mpz_t zero; - mpz_init_set_ui(zero, 0); - start = Expression::make_integer(&zero, NULL, location); - mpz_clear(zero); - } - - Expression* end = NULL; - if (this->peek_token()->is_op(OPERATOR_COLON)) - { - // We use nil to indicate a missing high expression. - if (this->advance_token()->is_op(OPERATOR_RSQUARE)) - end = Expression::make_nil(this->location()); - else - end = this->expression(PRECEDENCE_NORMAL, false, true, NULL, NULL); - } - if (!this->peek_token()->is_op(OPERATOR_RSQUARE)) - error_at(this->location(), "missing %<]%>"); - else - this->advance_token(); - return Expression::make_index(expr, start, end, location); -} - -// Call = "(" [ ArgumentList [ "," ] ] ")" . -// ArgumentList = ExpressionList [ "..." ] . - -Expression* -Parse::call(Expression* func) -{ - go_assert(this->peek_token()->is_op(OPERATOR_LPAREN)); - Expression_list* args = NULL; - bool is_varargs = false; - const Token* token = this->advance_token(); - if (!token->is_op(OPERATOR_RPAREN)) - { - args = this->expression_list(NULL, false, true); - token = this->peek_token(); - if (token->is_op(OPERATOR_ELLIPSIS)) - { - is_varargs = true; - token = this->advance_token(); - } - } - if (token->is_op(OPERATOR_COMMA)) - token = this->advance_token(); - if (!token->is_op(OPERATOR_RPAREN)) - error_at(this->location(), "missing %<)%>"); - else - this->advance_token(); - if (func->is_error_expression()) - return func; - return Expression::make_call(func, args, is_varargs, func->location()); -} - -// Return an expression for a single unqualified identifier. - -Expression* -Parse::id_to_expression(const std::string& name, Location location) -{ - Named_object* in_function; - Named_object* named_object = this->gogo_->lookup(name, &in_function); - if (named_object == NULL) - named_object = this->gogo_->add_unknown_name(name, location); - - if (in_function != NULL - && in_function != this->gogo_->current_function() - && (named_object->is_variable() || named_object->is_result_variable())) - return this->enclosing_var_reference(in_function, named_object, - location); - - switch (named_object->classification()) - { - case Named_object::NAMED_OBJECT_CONST: - return Expression::make_const_reference(named_object, location); - case Named_object::NAMED_OBJECT_VAR: - case Named_object::NAMED_OBJECT_RESULT_VAR: - this->mark_var_used(named_object); - return Expression::make_var_reference(named_object, location); - case Named_object::NAMED_OBJECT_SINK: - return Expression::make_sink(location); - case Named_object::NAMED_OBJECT_FUNC: - case Named_object::NAMED_OBJECT_FUNC_DECLARATION: - return Expression::make_func_reference(named_object, NULL, location); - case Named_object::NAMED_OBJECT_UNKNOWN: - { - Unknown_expression* ue = - Expression::make_unknown_reference(named_object, location); - if (this->is_erroneous_function_) - ue->set_no_error_message(); - return ue; - } - case Named_object::NAMED_OBJECT_PACKAGE: - case Named_object::NAMED_OBJECT_TYPE: - case Named_object::NAMED_OBJECT_TYPE_DECLARATION: - { - // These cases can arise for a field name in a composite - // literal. - Unknown_expression* ue = - Expression::make_unknown_reference(named_object, location); - if (this->is_erroneous_function_) - ue->set_no_error_message(); - return ue; - } - case Named_object::NAMED_OBJECT_ERRONEOUS: - return Expression::make_error(location); - default: - error_at(this->location(), "unexpected type of identifier"); - return Expression::make_error(location); - } -} - -// Expression = UnaryExpr { binary_op Expression } . - -// PRECEDENCE is the precedence of the current operator. - -// If MAY_BE_SINK is true, this expression may be "_". - -// If MAY_BE_COMPOSITE_LIT is true, this expression may be a composite -// literal. - -// If IS_TYPE_SWITCH is not NULL, this will recognize a type switch -// guard (var := expr.("type") using the literal keyword "type"). - -// If IS_PARENTHESIZED is not NULL, *IS_PARENTHESIZED is set to true -// if the entire expression is in parentheses. - -Expression* -Parse::expression(Precedence precedence, bool may_be_sink, - bool may_be_composite_lit, bool* is_type_switch, - bool *is_parenthesized) -{ - Expression* left = this->unary_expr(may_be_sink, may_be_composite_lit, - is_type_switch, is_parenthesized); - - while (true) - { - if (is_type_switch != NULL && *is_type_switch) - return left; - - const Token* token = this->peek_token(); - if (token->classification() != Token::TOKEN_OPERATOR) - { - // Not a binary_op. - return left; - } - - Precedence right_precedence; - switch (token->op()) - { - case OPERATOR_OROR: - right_precedence = PRECEDENCE_OROR; - break; - case OPERATOR_ANDAND: - right_precedence = PRECEDENCE_ANDAND; - break; - case OPERATOR_EQEQ: - case OPERATOR_NOTEQ: - case OPERATOR_LT: - case OPERATOR_LE: - case OPERATOR_GT: - case OPERATOR_GE: - right_precedence = PRECEDENCE_RELOP; - break; - case OPERATOR_PLUS: - case OPERATOR_MINUS: - case OPERATOR_OR: - case OPERATOR_XOR: - right_precedence = PRECEDENCE_ADDOP; - break; - case OPERATOR_MULT: - case OPERATOR_DIV: - case OPERATOR_MOD: - case OPERATOR_LSHIFT: - case OPERATOR_RSHIFT: - case OPERATOR_AND: - case OPERATOR_BITCLEAR: - right_precedence = PRECEDENCE_MULOP; - break; - default: - right_precedence = PRECEDENCE_INVALID; - break; - } - - if (right_precedence == PRECEDENCE_INVALID) - { - // Not a binary_op. - return left; - } - - if (is_parenthesized != NULL) - *is_parenthesized = false; - - Operator op = token->op(); - Location binop_location = token->location(); - - if (precedence >= right_precedence) - { - // We've already seen A * B, and we see + C. We want to - // return so that A * B becomes a group. - return left; - } - - this->advance_token(); - - left = this->verify_not_sink(left); - Expression* right = this->expression(right_precedence, false, - may_be_composite_lit, - NULL, NULL); - left = Expression::make_binary(op, left, right, binop_location); - } -} - -bool -Parse::expression_may_start_here() -{ - const Token* token = this->peek_token(); - switch (token->classification()) - { - case Token::TOKEN_INVALID: - case Token::TOKEN_EOF: - return false; - case Token::TOKEN_KEYWORD: - switch (token->keyword()) - { - case KEYWORD_CHAN: - case KEYWORD_FUNC: - case KEYWORD_MAP: - case KEYWORD_STRUCT: - case KEYWORD_INTERFACE: - return true; - default: - return false; - } - case Token::TOKEN_IDENTIFIER: - return true; - case Token::TOKEN_STRING: - return true; - case Token::TOKEN_OPERATOR: - switch (token->op()) - { - case OPERATOR_PLUS: - case OPERATOR_MINUS: - case OPERATOR_NOT: - case OPERATOR_XOR: - case OPERATOR_MULT: - case OPERATOR_CHANOP: - case OPERATOR_AND: - case OPERATOR_LPAREN: - case OPERATOR_LSQUARE: - return true; - default: - return false; - } - case Token::TOKEN_CHARACTER: - case Token::TOKEN_INTEGER: - case Token::TOKEN_FLOAT: - case Token::TOKEN_IMAGINARY: - return true; - default: - go_unreachable(); - } -} - -// UnaryExpr = unary_op UnaryExpr | PrimaryExpr . - -// If MAY_BE_SINK is true, this expression may be "_". - -// If MAY_BE_COMPOSITE_LIT is true, this expression may be a composite -// literal. - -// If IS_TYPE_SWITCH is not NULL, this will recognize a type switch -// guard (var := expr.("type") using the literal keyword "type"). - -// If IS_PARENTHESIZED is not NULL, *IS_PARENTHESIZED is set to true -// if the entire expression is in parentheses. - -Expression* -Parse::unary_expr(bool may_be_sink, bool may_be_composite_lit, - bool* is_type_switch, bool* is_parenthesized) -{ - const Token* token = this->peek_token(); - - // There is a complex parse for <- chan. The choices are - // Convert x to type <- chan int: - // (<- chan int)(x) - // Receive from (x converted to type chan <- chan int): - // (<- chan <- chan int (x)) - // Convert x to type <- chan (<- chan int). - // (<- chan <- chan int)(x) - if (token->is_op(OPERATOR_CHANOP)) - { - Location location = token->location(); - if (this->advance_token()->is_keyword(KEYWORD_CHAN)) - { - Expression* expr = this->primary_expr(false, may_be_composite_lit, - NULL, NULL); - if (expr->is_error_expression()) - return expr; - else if (!expr->is_type_expression()) - return Expression::make_receive(expr, location); - else - { - if (expr->type()->is_error_type()) - return expr; - - // We picked up "chan TYPE", but it is not a type - // conversion. - Channel_type* ct = expr->type()->channel_type(); - if (ct == NULL) - { - // This is probably impossible. - error_at(location, "expected channel type"); - return Expression::make_error(location); - } - else if (ct->may_receive()) - { - // <- chan TYPE. - Type* t = Type::make_channel_type(false, true, - ct->element_type()); - return Expression::make_type(t, location); - } - else - { - // <- chan <- TYPE. Because we skipped the leading - // <-, we parsed this as chan <- TYPE. With the - // leading <-, we parse it as <- chan (<- TYPE). - Type *t = this->reassociate_chan_direction(ct, location); - return Expression::make_type(t, location); - } - } - } - - this->unget_token(Token::make_operator_token(OPERATOR_CHANOP, location)); - token = this->peek_token(); - } - - if (token->is_op(OPERATOR_PLUS) - || token->is_op(OPERATOR_MINUS) - || token->is_op(OPERATOR_NOT) - || token->is_op(OPERATOR_XOR) - || token->is_op(OPERATOR_CHANOP) - || token->is_op(OPERATOR_MULT) - || token->is_op(OPERATOR_AND)) - { - Location location = token->location(); - Operator op = token->op(); - this->advance_token(); - - Expression* expr = this->unary_expr(false, may_be_composite_lit, NULL, - NULL); - if (expr->is_error_expression()) - ; - else if (op == OPERATOR_MULT && expr->is_type_expression()) - expr = Expression::make_type(Type::make_pointer_type(expr->type()), - location); - else if (op == OPERATOR_AND && expr->is_composite_literal()) - expr = Expression::make_heap_composite(expr, location); - else if (op != OPERATOR_CHANOP) - expr = Expression::make_unary(op, expr, location); - else - expr = Expression::make_receive(expr, location); - return expr; - } - else - return this->primary_expr(may_be_sink, may_be_composite_lit, - is_type_switch, is_parenthesized); -} - -// This is called for the obscure case of -// (<- chan <- chan int)(x) -// In unary_expr we remove the leading <- and parse the remainder, -// which gives us -// chan <- (chan int) -// When we add the leading <- back in, we really want -// <- chan (<- chan int) -// This means that we need to reassociate. - -Type* -Parse::reassociate_chan_direction(Channel_type *ct, Location location) -{ - Channel_type* ele = ct->element_type()->channel_type(); - if (ele == NULL) - { - error_at(location, "parse error"); - return Type::make_error_type(); - } - Type* sub = ele; - if (ele->may_send()) - sub = Type::make_channel_type(false, true, ele->element_type()); - else - sub = this->reassociate_chan_direction(ele, location); - return Type::make_channel_type(false, true, sub); -} - -// Statement = -// Declaration | LabeledStmt | SimpleStmt | -// GoStmt | ReturnStmt | BreakStmt | ContinueStmt | GotoStmt | -// FallthroughStmt | Block | IfStmt | SwitchStmt | SelectStmt | ForStmt | -// DeferStmt . - -// LABEL is the label of this statement if it has one. - -void -Parse::statement(Label* label) -{ - const Token* token = this->peek_token(); - switch (token->classification()) - { - case Token::TOKEN_KEYWORD: - { - switch (token->keyword()) - { - case KEYWORD_CONST: - case KEYWORD_TYPE: - case KEYWORD_VAR: - this->declaration(); - break; - case KEYWORD_FUNC: - case KEYWORD_MAP: - case KEYWORD_STRUCT: - case KEYWORD_INTERFACE: - this->simple_stat(true, NULL, NULL, NULL); - break; - case KEYWORD_GO: - case KEYWORD_DEFER: - this->go_or_defer_stat(); - break; - case KEYWORD_RETURN: - this->return_stat(); - break; - case KEYWORD_BREAK: - this->break_stat(); - break; - case KEYWORD_CONTINUE: - this->continue_stat(); - break; - case KEYWORD_GOTO: - this->goto_stat(); - break; - case KEYWORD_IF: - this->if_stat(); - break; - case KEYWORD_SWITCH: - this->switch_stat(label); - break; - case KEYWORD_SELECT: - this->select_stat(label); - break; - case KEYWORD_FOR: - this->for_stat(label); - break; - default: - error_at(this->location(), "expected statement"); - this->advance_token(); - break; - } - } - break; - - case Token::TOKEN_IDENTIFIER: - { - std::string identifier = token->identifier(); - bool is_exported = token->is_identifier_exported(); - Location location = token->location(); - if (this->advance_token()->is_op(OPERATOR_COLON)) - { - this->advance_token(); - this->labeled_stmt(identifier, location); - } - else - { - this->unget_token(Token::make_identifier_token(identifier, - is_exported, - location)); - this->simple_stat(true, NULL, NULL, NULL); - } - } - break; - - case Token::TOKEN_OPERATOR: - if (token->is_op(OPERATOR_LCURLY)) - { - Location location = token->location(); - this->gogo_->start_block(location); - Location end_loc = this->block(); - this->gogo_->add_block(this->gogo_->finish_block(end_loc), - location); - } - else if (!token->is_op(OPERATOR_SEMICOLON)) - this->simple_stat(true, NULL, NULL, NULL); - break; - - case Token::TOKEN_STRING: - case Token::TOKEN_CHARACTER: - case Token::TOKEN_INTEGER: - case Token::TOKEN_FLOAT: - case Token::TOKEN_IMAGINARY: - this->simple_stat(true, NULL, NULL, NULL); - break; - - default: - error_at(this->location(), "expected statement"); - this->advance_token(); - break; - } -} - -bool -Parse::statement_may_start_here() -{ - const Token* token = this->peek_token(); - switch (token->classification()) - { - case Token::TOKEN_KEYWORD: - { - switch (token->keyword()) - { - case KEYWORD_CONST: - case KEYWORD_TYPE: - case KEYWORD_VAR: - case KEYWORD_FUNC: - case KEYWORD_MAP: - case KEYWORD_STRUCT: - case KEYWORD_INTERFACE: - case KEYWORD_GO: - case KEYWORD_DEFER: - case KEYWORD_RETURN: - case KEYWORD_BREAK: - case KEYWORD_CONTINUE: - case KEYWORD_GOTO: - case KEYWORD_IF: - case KEYWORD_SWITCH: - case KEYWORD_SELECT: - case KEYWORD_FOR: - return true; - - default: - return false; - } - } - break; - - case Token::TOKEN_IDENTIFIER: - return true; - - case Token::TOKEN_OPERATOR: - if (token->is_op(OPERATOR_LCURLY) - || token->is_op(OPERATOR_SEMICOLON)) - return true; - else - return this->expression_may_start_here(); - - case Token::TOKEN_STRING: - case Token::TOKEN_CHARACTER: - case Token::TOKEN_INTEGER: - case Token::TOKEN_FLOAT: - case Token::TOKEN_IMAGINARY: - return true; - - default: - return false; - } -} - -// LabeledStmt = Label ":" Statement . -// Label = identifier . - -void -Parse::labeled_stmt(const std::string& label_name, Location location) -{ - Label* label = this->gogo_->add_label_definition(label_name, location); - - if (this->peek_token()->is_op(OPERATOR_RCURLY)) - { - // This is a label at the end of a block. A program is - // permitted to omit a semicolon here. - return; - } - - if (!this->statement_may_start_here()) - { - // Mark the label as used to avoid a useless error about an - // unused label. - label->set_is_used(); - - error_at(location, "missing statement after label"); - this->unget_token(Token::make_operator_token(OPERATOR_SEMICOLON, - location)); - return; - } - - this->statement(label); -} - -// SimpleStmt = EmptyStmt | ExpressionStmt | SendStmt | IncDecStmt | -// Assignment | ShortVarDecl . - -// EmptyStmt was handled in Parse::statement. - -// In order to make this work for if and switch statements, if -// RETURN_EXP is not NULL, and we see an ExpressionStat, we return the -// expression rather than adding an expression statement to the -// current block. If we see something other than an ExpressionStat, -// we add the statement, set *RETURN_EXP to true if we saw a send -// statement, and return NULL. The handling of send statements is for -// better error messages. - -// If P_RANGE_CLAUSE is not NULL, then this will recognize a -// RangeClause. - -// If P_TYPE_SWITCH is not NULL, this will recognize a type switch -// guard (var := expr.("type") using the literal keyword "type"). - -Expression* -Parse::simple_stat(bool may_be_composite_lit, bool* return_exp, - Range_clause* p_range_clause, Type_switch* p_type_switch) -{ - const Token* token = this->peek_token(); - - // An identifier follow by := is a SimpleVarDecl. - if (token->is_identifier()) - { - std::string identifier = token->identifier(); - bool is_exported = token->is_identifier_exported(); - Location location = token->location(); - - token = this->advance_token(); - if (token->is_op(OPERATOR_COLONEQ) - || token->is_op(OPERATOR_COMMA)) - { - identifier = this->gogo_->pack_hidden_name(identifier, is_exported); - this->simple_var_decl_or_assignment(identifier, location, - may_be_composite_lit, - p_range_clause, - (token->is_op(OPERATOR_COLONEQ) - ? p_type_switch - : NULL)); - return NULL; - } - - this->unget_token(Token::make_identifier_token(identifier, is_exported, - location)); - } - - Expression* exp = this->expression(PRECEDENCE_NORMAL, true, - may_be_composite_lit, - (p_type_switch == NULL - ? NULL - : &p_type_switch->found), - NULL); - if (p_type_switch != NULL && p_type_switch->found) - { - p_type_switch->name.clear(); - p_type_switch->location = exp->location(); - p_type_switch->expr = this->verify_not_sink(exp); - return NULL; - } - token = this->peek_token(); - if (token->is_op(OPERATOR_CHANOP)) - { - this->send_stmt(this->verify_not_sink(exp)); - if (return_exp != NULL) - *return_exp = true; - } - else if (token->is_op(OPERATOR_PLUSPLUS) - || token->is_op(OPERATOR_MINUSMINUS)) - this->inc_dec_stat(this->verify_not_sink(exp)); - else if (token->is_op(OPERATOR_COMMA) - || token->is_op(OPERATOR_EQ)) - this->assignment(exp, may_be_composite_lit, p_range_clause); - else if (token->is_op(OPERATOR_PLUSEQ) - || token->is_op(OPERATOR_MINUSEQ) - || token->is_op(OPERATOR_OREQ) - || token->is_op(OPERATOR_XOREQ) - || token->is_op(OPERATOR_MULTEQ) - || token->is_op(OPERATOR_DIVEQ) - || token->is_op(OPERATOR_MODEQ) - || token->is_op(OPERATOR_LSHIFTEQ) - || token->is_op(OPERATOR_RSHIFTEQ) - || token->is_op(OPERATOR_ANDEQ) - || token->is_op(OPERATOR_BITCLEAREQ)) - this->assignment(this->verify_not_sink(exp), may_be_composite_lit, - p_range_clause); - else if (return_exp != NULL) - return this->verify_not_sink(exp); - else - { - exp = this->verify_not_sink(exp); - - if (token->is_op(OPERATOR_COLONEQ)) - { - if (!exp->is_error_expression()) - error_at(token->location(), "non-name on left side of %<:=%>"); - this->gogo_->mark_locals_used(); - while (!token->is_op(OPERATOR_SEMICOLON) - && !token->is_eof()) - token = this->advance_token(); - return NULL; - } - - this->expression_stat(exp); - } - - return NULL; -} - -bool -Parse::simple_stat_may_start_here() -{ - return this->expression_may_start_here(); -} - -// Parse { Statement ";" } which is used in a few places. The list of -// statements may end with a right curly brace, in which case the -// semicolon may be omitted. - -void -Parse::statement_list() -{ - while (this->statement_may_start_here()) - { - this->statement(NULL); - if (this->peek_token()->is_op(OPERATOR_SEMICOLON)) - this->advance_token(); - else if (this->peek_token()->is_op(OPERATOR_RCURLY)) - break; - else - { - if (!this->peek_token()->is_eof() || !saw_errors()) - error_at(this->location(), "expected %<;%> or %<}%> or newline"); - if (!this->skip_past_error(OPERATOR_RCURLY)) - return; - } - } -} - -bool -Parse::statement_list_may_start_here() -{ - return this->statement_may_start_here(); -} - -// ExpressionStat = Expression . - -void -Parse::expression_stat(Expression* exp) -{ - this->gogo_->add_statement(Statement::make_statement(exp, false)); -} - -// SendStmt = Channel "<-" Expression . -// Channel = Expression . - -void -Parse::send_stmt(Expression* channel) -{ - go_assert(this->peek_token()->is_op(OPERATOR_CHANOP)); - Location loc = this->location(); - this->advance_token(); - Expression* val = this->expression(PRECEDENCE_NORMAL, false, true, NULL, - NULL); - Statement* s = Statement::make_send_statement(channel, val, loc); - this->gogo_->add_statement(s); -} - -// IncDecStat = Expression ( "++" | "--" ) . - -void -Parse::inc_dec_stat(Expression* exp) -{ - const Token* token = this->peek_token(); - - // Lvalue maps require special handling. - if (exp->index_expression() != NULL) - exp->index_expression()->set_is_lvalue(); - - if (token->is_op(OPERATOR_PLUSPLUS)) - this->gogo_->add_statement(Statement::make_inc_statement(exp)); - else if (token->is_op(OPERATOR_MINUSMINUS)) - this->gogo_->add_statement(Statement::make_dec_statement(exp)); - else - go_unreachable(); - this->advance_token(); -} - -// Assignment = ExpressionList assign_op ExpressionList . - -// EXP is an expression that we have already parsed. - -// If MAY_BE_COMPOSITE_LIT is true, an expression on the right hand -// side may be a composite literal. - -// If RANGE_CLAUSE is not NULL, then this will recognize a -// RangeClause. - -void -Parse::assignment(Expression* expr, bool may_be_composite_lit, - Range_clause* p_range_clause) -{ - Expression_list* vars; - if (!this->peek_token()->is_op(OPERATOR_COMMA)) - { - vars = new Expression_list(); - vars->push_back(expr); - } - else - { - this->advance_token(); - vars = this->expression_list(expr, true, may_be_composite_lit); - } - - this->tuple_assignment(vars, may_be_composite_lit, p_range_clause); -} - -// An assignment statement. LHS is the list of expressions which -// appear on the left hand side. - -// If MAY_BE_COMPOSITE_LIT is true, an expression on the right hand -// side may be a composite literal. - -// If RANGE_CLAUSE is not NULL, then this will recognize a -// RangeClause. - -void -Parse::tuple_assignment(Expression_list* lhs, bool may_be_composite_lit, - Range_clause* p_range_clause) -{ - const Token* token = this->peek_token(); - if (!token->is_op(OPERATOR_EQ) - && !token->is_op(OPERATOR_PLUSEQ) - && !token->is_op(OPERATOR_MINUSEQ) - && !token->is_op(OPERATOR_OREQ) - && !token->is_op(OPERATOR_XOREQ) - && !token->is_op(OPERATOR_MULTEQ) - && !token->is_op(OPERATOR_DIVEQ) - && !token->is_op(OPERATOR_MODEQ) - && !token->is_op(OPERATOR_LSHIFTEQ) - && !token->is_op(OPERATOR_RSHIFTEQ) - && !token->is_op(OPERATOR_ANDEQ) - && !token->is_op(OPERATOR_BITCLEAREQ)) - { - error_at(this->location(), "expected assignment operator"); - return; - } - Operator op = token->op(); - Location location = token->location(); - - token = this->advance_token(); - - if (p_range_clause != NULL && token->is_keyword(KEYWORD_RANGE)) - { - if (op != OPERATOR_EQ) - error_at(this->location(), "range clause requires %<=%>"); - this->range_clause_expr(lhs, p_range_clause); - return; - } - - Expression_list* vals = this->expression_list(NULL, false, - may_be_composite_lit); - - // We've parsed everything; check for errors. - if (lhs == NULL || vals == NULL) - return; - for (Expression_list::const_iterator pe = lhs->begin(); - pe != lhs->end(); - ++pe) - { - if ((*pe)->is_error_expression()) - return; - if (op != OPERATOR_EQ && (*pe)->is_sink_expression()) - error_at((*pe)->location(), "cannot use _ as value"); - } - for (Expression_list::const_iterator pe = vals->begin(); - pe != vals->end(); - ++pe) - { - if ((*pe)->is_error_expression()) - return; - } - - // Map expressions act differently when they are lvalues. - for (Expression_list::iterator plv = lhs->begin(); - plv != lhs->end(); - ++plv) - if ((*plv)->index_expression() != NULL) - (*plv)->index_expression()->set_is_lvalue(); - - Call_expression* call; - Index_expression* map_index; - Receive_expression* receive; - Type_guard_expression* type_guard; - if (lhs->size() == vals->size()) - { - Statement* s; - if (lhs->size() > 1) - { - if (op != OPERATOR_EQ) - error_at(location, "multiple values only permitted with %<=%>"); - s = Statement::make_tuple_assignment(lhs, vals, location); - } - else - { - if (op == OPERATOR_EQ) - s = Statement::make_assignment(lhs->front(), vals->front(), - location); - else - s = Statement::make_assignment_operation(op, lhs->front(), - vals->front(), location); - delete lhs; - delete vals; - } - this->gogo_->add_statement(s); - } - else if (vals->size() == 1 - && (call = (*vals->begin())->call_expression()) != NULL) - { - if (op != OPERATOR_EQ) - error_at(location, "multiple results only permitted with %<=%>"); - delete vals; - vals = new Expression_list; - for (unsigned int i = 0; i < lhs->size(); ++i) - vals->push_back(Expression::make_call_result(call, i)); - Statement* s = Statement::make_tuple_assignment(lhs, vals, location); - this->gogo_->add_statement(s); - } - else if (lhs->size() == 2 - && vals->size() == 1 - && (map_index = (*vals->begin())->index_expression()) != NULL) - { - if (op != OPERATOR_EQ) - error_at(location, "two values from map requires %<=%>"); - Expression* val = lhs->front(); - Expression* present = lhs->back(); - Statement* s = Statement::make_tuple_map_assignment(val, present, - map_index, location); - this->gogo_->add_statement(s); - } - else if (lhs->size() == 1 - && vals->size() == 2 - && (map_index = lhs->front()->index_expression()) != NULL) - { - if (op != OPERATOR_EQ) - error_at(location, "assigning tuple to map index requires %<=%>"); - Expression* val = vals->front(); - Expression* should_set = vals->back(); - Statement* s = Statement::make_map_assignment(map_index, val, should_set, - location); - this->gogo_->add_statement(s); - } - else if (lhs->size() == 2 - && vals->size() == 1 - && (receive = (*vals->begin())->receive_expression()) != NULL) - { - if (op != OPERATOR_EQ) - error_at(location, "two values from receive requires %<=%>"); - Expression* val = lhs->front(); - Expression* success = lhs->back(); - Expression* channel = receive->channel(); - Statement* s = Statement::make_tuple_receive_assignment(val, success, - channel, - location); - this->gogo_->add_statement(s); - } - else if (lhs->size() == 2 - && vals->size() == 1 - && (type_guard = (*vals->begin())->type_guard_expression()) != NULL) - { - if (op != OPERATOR_EQ) - error_at(location, "two values from type guard requires %<=%>"); - Expression* val = lhs->front(); - Expression* ok = lhs->back(); - Expression* expr = type_guard->expr(); - Type* type = type_guard->type(); - Statement* s = Statement::make_tuple_type_guard_assignment(val, ok, - expr, type, - location); - this->gogo_->add_statement(s); - } - else - { - error_at(location, "number of variables does not match number of values"); - } -} - -// GoStat = "go" Expression . -// DeferStat = "defer" Expression . - -void -Parse::go_or_defer_stat() -{ - go_assert(this->peek_token()->is_keyword(KEYWORD_GO) - || this->peek_token()->is_keyword(KEYWORD_DEFER)); - bool is_go = this->peek_token()->is_keyword(KEYWORD_GO); - Location stat_location = this->location(); - - this->advance_token(); - Location expr_location = this->location(); - - bool is_parenthesized = false; - Expression* expr = this->expression(PRECEDENCE_NORMAL, false, true, NULL, - &is_parenthesized); - Call_expression* call_expr = expr->call_expression(); - if (is_parenthesized || call_expr == NULL) - { - error_at(expr_location, "argument to go/defer must be function call"); - return; - } - - // Make it easier to simplify go/defer statements by putting every - // statement in its own block. - this->gogo_->start_block(stat_location); - Statement* stat; - if (is_go) - stat = Statement::make_go_statement(call_expr, stat_location); - else - stat = Statement::make_defer_statement(call_expr, stat_location); - this->gogo_->add_statement(stat); - this->gogo_->add_block(this->gogo_->finish_block(stat_location), - stat_location); -} - -// ReturnStat = "return" [ ExpressionList ] . - -void -Parse::return_stat() -{ - go_assert(this->peek_token()->is_keyword(KEYWORD_RETURN)); - Location location = this->location(); - this->advance_token(); - Expression_list* vals = NULL; - if (this->expression_may_start_here()) - vals = this->expression_list(NULL, false, true); - this->gogo_->add_statement(Statement::make_return_statement(vals, location)); - - if (vals == NULL - && this->gogo_->current_function()->func_value()->results_are_named()) - { - Named_object* function = this->gogo_->current_function(); - Function::Results* results = function->func_value()->result_variables(); - for (Function::Results::const_iterator p = results->begin(); - p != results->end(); - ++p) - { - Named_object* no = this->gogo_->lookup((*p)->name(), NULL); - if (no == NULL) - go_assert(saw_errors()); - else if (!no->is_result_variable()) - error_at(location, "%qs is shadowed during return", - (*p)->message_name().c_str()); - } - } -} - -// IfStmt = "if" [ SimpleStmt ";" ] Expression Block -// [ "else" ( IfStmt | Block ) ] . - -void -Parse::if_stat() -{ - go_assert(this->peek_token()->is_keyword(KEYWORD_IF)); - Location location = this->location(); - this->advance_token(); - - this->gogo_->start_block(location); - - bool saw_simple_stat = false; - Expression* cond = NULL; - bool saw_send_stmt = false; - if (this->simple_stat_may_start_here()) - { - cond = this->simple_stat(false, &saw_send_stmt, NULL, NULL); - saw_simple_stat = true; - } - if (cond != NULL && this->peek_token()->is_op(OPERATOR_SEMICOLON)) - { - // The SimpleStat is an expression statement. - this->expression_stat(cond); - cond = NULL; - } - if (cond == NULL) - { - if (this->peek_token()->is_op(OPERATOR_SEMICOLON)) - this->advance_token(); - else if (saw_simple_stat) - { - if (saw_send_stmt) - error_at(this->location(), - ("send statement used as value; " - "use select for non-blocking send")); - else - error_at(this->location(), - "expected %<;%> after statement in if expression"); - if (!this->expression_may_start_here()) - cond = Expression::make_error(this->location()); - } - if (cond == NULL && this->peek_token()->is_op(OPERATOR_LCURLY)) - { - error_at(this->location(), - "missing condition in if statement"); - cond = Expression::make_error(this->location()); - } - if (cond == NULL) - cond = this->expression(PRECEDENCE_NORMAL, false, false, NULL, NULL); - } - - this->gogo_->start_block(this->location()); - Location end_loc = this->block(); - Block* then_block = this->gogo_->finish_block(end_loc); - - // Check for the easy error of a newline before "else". - if (this->peek_token()->is_op(OPERATOR_SEMICOLON)) - { - Location semi_loc = this->location(); - if (this->advance_token()->is_keyword(KEYWORD_ELSE)) - error_at(this->location(), - "unexpected semicolon or newline before %<else%>"); - else - this->unget_token(Token::make_operator_token(OPERATOR_SEMICOLON, - semi_loc)); - } - - Block* else_block = NULL; - if (this->peek_token()->is_keyword(KEYWORD_ELSE)) - { - this->gogo_->start_block(this->location()); - const Token* token = this->advance_token(); - if (token->is_keyword(KEYWORD_IF)) - this->if_stat(); - else if (token->is_op(OPERATOR_LCURLY)) - this->block(); - else - { - error_at(this->location(), "expected %<if%> or %<{%>"); - this->statement(NULL); - } - else_block = this->gogo_->finish_block(this->location()); - } - - this->gogo_->add_statement(Statement::make_if_statement(cond, then_block, - else_block, - location)); - - this->gogo_->add_block(this->gogo_->finish_block(this->location()), - location); -} - -// SwitchStmt = ExprSwitchStmt | TypeSwitchStmt . -// ExprSwitchStmt = "switch" [ [ SimpleStat ] ";" ] [ Expression ] -// "{" { ExprCaseClause } "}" . -// TypeSwitchStmt = "switch" [ [ SimpleStat ] ";" ] TypeSwitchGuard -// "{" { TypeCaseClause } "}" . -// TypeSwitchGuard = [ identifier ":=" ] Expression "." "(" "type" ")" . - -void -Parse::switch_stat(Label* label) -{ - go_assert(this->peek_token()->is_keyword(KEYWORD_SWITCH)); - Location location = this->location(); - this->advance_token(); - - this->gogo_->start_block(location); - - bool saw_simple_stat = false; - Expression* switch_val = NULL; - bool saw_send_stmt; - Type_switch type_switch; - bool have_type_switch_block = false; - if (this->simple_stat_may_start_here()) - { - switch_val = this->simple_stat(false, &saw_send_stmt, NULL, - &type_switch); - saw_simple_stat = true; - } - if (switch_val != NULL && this->peek_token()->is_op(OPERATOR_SEMICOLON)) - { - // The SimpleStat is an expression statement. - this->expression_stat(switch_val); - switch_val = NULL; - } - if (switch_val == NULL && !type_switch.found) - { - if (this->peek_token()->is_op(OPERATOR_SEMICOLON)) - this->advance_token(); - else if (saw_simple_stat) - { - if (saw_send_stmt) - error_at(this->location(), - ("send statement used as value; " - "use select for non-blocking send")); - else - error_at(this->location(), - "expected %<;%> after statement in switch expression"); - } - if (!this->peek_token()->is_op(OPERATOR_LCURLY)) - { - if (this->peek_token()->is_identifier()) - { - const Token* token = this->peek_token(); - std::string identifier = token->identifier(); - bool is_exported = token->is_identifier_exported(); - Location id_loc = token->location(); - - token = this->advance_token(); - bool is_coloneq = token->is_op(OPERATOR_COLONEQ); - this->unget_token(Token::make_identifier_token(identifier, - is_exported, - id_loc)); - if (is_coloneq) - { - // This must be a TypeSwitchGuard. It is in a - // different block from any initial SimpleStat. - if (saw_simple_stat) - { - this->gogo_->start_block(id_loc); - have_type_switch_block = true; - } - - switch_val = this->simple_stat(false, &saw_send_stmt, NULL, - &type_switch); - if (!type_switch.found) - { - if (switch_val == NULL - || !switch_val->is_error_expression()) - { - error_at(id_loc, "expected type switch assignment"); - switch_val = Expression::make_error(id_loc); - } - } - } - } - if (switch_val == NULL && !type_switch.found) - { - switch_val = this->expression(PRECEDENCE_NORMAL, false, false, - &type_switch.found, NULL); - if (type_switch.found) - { - type_switch.name.clear(); - type_switch.expr = switch_val; - type_switch.location = switch_val->location(); - } - } - } - } - - if (!this->peek_token()->is_op(OPERATOR_LCURLY)) - { - Location token_loc = this->location(); - if (this->peek_token()->is_op(OPERATOR_SEMICOLON) - && this->advance_token()->is_op(OPERATOR_LCURLY)) - error_at(token_loc, "unexpected semicolon or newline before %<{%>"); - else if (this->peek_token()->is_op(OPERATOR_COLONEQ)) - { - error_at(token_loc, "invalid variable name"); - this->advance_token(); - this->expression(PRECEDENCE_NORMAL, false, false, - &type_switch.found, NULL); - if (this->peek_token()->is_op(OPERATOR_SEMICOLON)) - this->advance_token(); - if (!this->peek_token()->is_op(OPERATOR_LCURLY)) - { - if (have_type_switch_block) - this->gogo_->add_block(this->gogo_->finish_block(location), - location); - this->gogo_->add_block(this->gogo_->finish_block(location), - location); - return; - } - if (type_switch.found) - type_switch.expr = Expression::make_error(location); - } - else - { - error_at(this->location(), "expected %<{%>"); - if (have_type_switch_block) - this->gogo_->add_block(this->gogo_->finish_block(this->location()), - location); - this->gogo_->add_block(this->gogo_->finish_block(this->location()), - location); - return; - } - } - this->advance_token(); - - Statement* statement; - if (type_switch.found) - statement = this->type_switch_body(label, type_switch, location); - else - statement = this->expr_switch_body(label, switch_val, location); - - if (statement != NULL) - this->gogo_->add_statement(statement); - - if (have_type_switch_block) - this->gogo_->add_block(this->gogo_->finish_block(this->location()), - location); - - this->gogo_->add_block(this->gogo_->finish_block(this->location()), - location); -} - -// The body of an expression switch. -// "{" { ExprCaseClause } "}" - -Statement* -Parse::expr_switch_body(Label* label, Expression* switch_val, - Location location) -{ - Switch_statement* statement = Statement::make_switch_statement(switch_val, - location); - - this->push_break_statement(statement, label); - - Case_clauses* case_clauses = new Case_clauses(); - bool saw_default = false; - while (!this->peek_token()->is_op(OPERATOR_RCURLY)) - { - if (this->peek_token()->is_eof()) - { - if (!saw_errors()) - error_at(this->location(), "missing %<}%>"); - return NULL; - } - this->expr_case_clause(case_clauses, &saw_default); - } - this->advance_token(); - - statement->add_clauses(case_clauses); - - this->pop_break_statement(); - - return statement; -} - -// ExprCaseClause = ExprSwitchCase ":" [ StatementList ] . -// FallthroughStat = "fallthrough" . - -void -Parse::expr_case_clause(Case_clauses* clauses, bool* saw_default) -{ - Location location = this->location(); - - bool is_default = false; - Expression_list* vals = this->expr_switch_case(&is_default); - - if (!this->peek_token()->is_op(OPERATOR_COLON)) - { - if (!saw_errors()) - error_at(this->location(), "expected %<:%>"); - return; - } - else - this->advance_token(); - - Block* statements = NULL; - if (this->statement_list_may_start_here()) - { - this->gogo_->start_block(this->location()); - this->statement_list(); - statements = this->gogo_->finish_block(this->location()); - } - - bool is_fallthrough = false; - if (this->peek_token()->is_keyword(KEYWORD_FALLTHROUGH)) - { - is_fallthrough = true; - if (this->advance_token()->is_op(OPERATOR_SEMICOLON)) - this->advance_token(); - } - - if (is_default) - { - if (*saw_default) - { - error_at(location, "multiple defaults in switch"); - return; - } - *saw_default = true; - } - - if (is_default || vals != NULL) - clauses->add(vals, is_default, statements, is_fallthrough, location); -} - -// ExprSwitchCase = "case" ExpressionList | "default" . - -Expression_list* -Parse::expr_switch_case(bool* is_default) -{ - const Token* token = this->peek_token(); - if (token->is_keyword(KEYWORD_CASE)) - { - this->advance_token(); - return this->expression_list(NULL, false, true); - } - else if (token->is_keyword(KEYWORD_DEFAULT)) - { - this->advance_token(); - *is_default = true; - return NULL; - } - else - { - if (!saw_errors()) - error_at(this->location(), "expected %<case%> or %<default%>"); - if (!token->is_op(OPERATOR_RCURLY)) - this->advance_token(); - return NULL; - } -} - -// The body of a type switch. -// "{" { TypeCaseClause } "}" . - -Statement* -Parse::type_switch_body(Label* label, const Type_switch& type_switch, - Location location) -{ - Named_object* switch_no = NULL; - if (!type_switch.name.empty()) - { - if (Gogo::is_sink_name(type_switch.name)) - error_at(type_switch.location, - "no new variables on left side of %<:=%>"); - else - { - Variable* switch_var = new Variable(NULL, type_switch.expr, false, - false, false, - type_switch.location); - switch_no = this->gogo_->add_variable(type_switch.name, switch_var); - } - } - - Type_switch_statement* statement = - Statement::make_type_switch_statement(switch_no, - (switch_no == NULL - ? type_switch.expr - : NULL), - location); - - this->push_break_statement(statement, label); - - Type_case_clauses* case_clauses = new Type_case_clauses(); - bool saw_default = false; - while (!this->peek_token()->is_op(OPERATOR_RCURLY)) - { - if (this->peek_token()->is_eof()) - { - error_at(this->location(), "missing %<}%>"); - return NULL; - } - this->type_case_clause(switch_no, case_clauses, &saw_default); - } - this->advance_token(); - - statement->add_clauses(case_clauses); - - this->pop_break_statement(); - - return statement; -} - -// TypeCaseClause = TypeSwitchCase ":" [ StatementList ] . - -void -Parse::type_case_clause(Named_object* switch_no, Type_case_clauses* clauses, - bool* saw_default) -{ - Location location = this->location(); - - std::vector<Type*> types; - bool is_default = false; - this->type_switch_case(&types, &is_default); - - if (!this->peek_token()->is_op(OPERATOR_COLON)) - error_at(this->location(), "expected %<:%>"); - else - this->advance_token(); - - Block* statements = NULL; - if (this->statement_list_may_start_here()) - { - this->gogo_->start_block(this->location()); - if (switch_no != NULL && types.size() == 1) - { - Type* type = types.front(); - Expression* init = Expression::make_var_reference(switch_no, - location); - init = Expression::make_type_guard(init, type, location); - Variable* v = new Variable(type, init, false, false, false, - location); - v->set_is_type_switch_var(); - Named_object* no = this->gogo_->add_variable(switch_no->name(), v); - - // We don't want to issue an error if the compiler - // introduced special variable is not used. Instead we want - // to issue an error if the variable defined by the switch - // is not used. That is handled via type_switch_vars_ and - // Parse::mark_var_used. - v->set_is_used(); - this->type_switch_vars_[no] = switch_no; - } - this->statement_list(); - statements = this->gogo_->finish_block(this->location()); - } - - if (this->peek_token()->is_keyword(KEYWORD_FALLTHROUGH)) - { - error_at(this->location(), - "fallthrough is not permitted in a type switch"); - if (this->advance_token()->is_op(OPERATOR_SEMICOLON)) - this->advance_token(); - } - - if (is_default) - { - go_assert(types.empty()); - if (*saw_default) - { - error_at(location, "multiple defaults in type switch"); - return; - } - *saw_default = true; - clauses->add(NULL, false, true, statements, location); - } - else if (!types.empty()) - { - for (std::vector<Type*>::const_iterator p = types.begin(); - p + 1 != types.end(); - ++p) - clauses->add(*p, true, false, NULL, location); - clauses->add(types.back(), false, false, statements, location); - } - else - clauses->add(Type::make_error_type(), false, false, statements, location); -} - -// TypeSwitchCase = "case" type | "default" - -// We accept a comma separated list of types. - -void -Parse::type_switch_case(std::vector<Type*>* types, bool* is_default) -{ - const Token* token = this->peek_token(); - if (token->is_keyword(KEYWORD_CASE)) - { - this->advance_token(); - while (true) - { - Type* t = this->type(); - - if (!t->is_error_type()) - types->push_back(t); - else - { - this->gogo_->mark_locals_used(); - token = this->peek_token(); - while (!token->is_op(OPERATOR_COLON) - && !token->is_op(OPERATOR_COMMA) - && !token->is_op(OPERATOR_RCURLY) - && !token->is_eof()) - token = this->advance_token(); - } - - if (!this->peek_token()->is_op(OPERATOR_COMMA)) - break; - this->advance_token(); - } - } - else if (token->is_keyword(KEYWORD_DEFAULT)) - { - this->advance_token(); - *is_default = true; - } - else - { - error_at(this->location(), "expected %<case%> or %<default%>"); - if (!token->is_op(OPERATOR_RCURLY)) - this->advance_token(); - } -} - -// SelectStat = "select" "{" { CommClause } "}" . - -void -Parse::select_stat(Label* label) -{ - go_assert(this->peek_token()->is_keyword(KEYWORD_SELECT)); - Location location = this->location(); - const Token* token = this->advance_token(); - - if (!token->is_op(OPERATOR_LCURLY)) - { - Location token_loc = token->location(); - if (token->is_op(OPERATOR_SEMICOLON) - && this->advance_token()->is_op(OPERATOR_LCURLY)) - error_at(token_loc, "unexpected semicolon or newline before %<{%>"); - else - { - error_at(this->location(), "expected %<{%>"); - return; - } - } - this->advance_token(); - - Select_statement* statement = Statement::make_select_statement(location); - - this->push_break_statement(statement, label); - - Select_clauses* select_clauses = new Select_clauses(); - bool saw_default = false; - while (!this->peek_token()->is_op(OPERATOR_RCURLY)) - { - if (this->peek_token()->is_eof()) - { - error_at(this->location(), "expected %<}%>"); - return; - } - this->comm_clause(select_clauses, &saw_default); - } - - this->advance_token(); - - statement->add_clauses(select_clauses); - - this->pop_break_statement(); - - this->gogo_->add_statement(statement); -} - -// CommClause = CommCase ":" { Statement ";" } . - -void -Parse::comm_clause(Select_clauses* clauses, bool* saw_default) -{ - Location location = this->location(); - bool is_send = false; - Expression* channel = NULL; - Expression* val = NULL; - Expression* closed = NULL; - std::string varname; - std::string closedname; - bool is_default = false; - bool got_case = this->comm_case(&is_send, &channel, &val, &closed, - &varname, &closedname, &is_default); - - if (!is_send - && varname.empty() - && closedname.empty() - && val != NULL - && val->index_expression() != NULL) - val->index_expression()->set_is_lvalue(); - - if (this->peek_token()->is_op(OPERATOR_COLON)) - this->advance_token(); - else - error_at(this->location(), "expected colon"); - - this->gogo_->start_block(this->location()); - - Named_object* var = NULL; - if (!varname.empty()) - { - // FIXME: LOCATION is slightly wrong here. - Variable* v = new Variable(NULL, channel, false, false, false, - location); - v->set_type_from_chan_element(); - var = this->gogo_->add_variable(varname, v); - } - - Named_object* closedvar = NULL; - if (!closedname.empty()) - { - // FIXME: LOCATION is slightly wrong here. - Variable* v = new Variable(Type::lookup_bool_type(), NULL, - false, false, false, location); - closedvar = this->gogo_->add_variable(closedname, v); - } - - this->statement_list(); - - Block* statements = this->gogo_->finish_block(this->location()); - - if (is_default) - { - if (*saw_default) - { - error_at(location, "multiple defaults in select"); - return; - } - *saw_default = true; - } - - if (got_case) - clauses->add(is_send, channel, val, closed, var, closedvar, is_default, - statements, location); - else if (statements != NULL) - { - // Add the statements to make sure that any names they define - // are traversed. - this->gogo_->add_block(statements, location); - } -} - -// CommCase = "case" ( SendStmt | RecvStmt ) | "default" . - -bool -Parse::comm_case(bool* is_send, Expression** channel, Expression** val, - Expression** closed, std::string* varname, - std::string* closedname, bool* is_default) -{ - const Token* token = this->peek_token(); - if (token->is_keyword(KEYWORD_DEFAULT)) - { - this->advance_token(); - *is_default = true; - } - else if (token->is_keyword(KEYWORD_CASE)) - { - this->advance_token(); - if (!this->send_or_recv_stmt(is_send, channel, val, closed, varname, - closedname)) - return false; - } - else - { - error_at(this->location(), "expected %<case%> or %<default%>"); - if (!token->is_op(OPERATOR_RCURLY)) - this->advance_token(); - return false; - } - - return true; -} - -// RecvStmt = [ Expression [ "," Expression ] ( "=" | ":=" ) ] RecvExpr . -// RecvExpr = Expression . - -bool -Parse::send_or_recv_stmt(bool* is_send, Expression** channel, Expression** val, - Expression** closed, std::string* varname, - std::string* closedname) -{ - const Token* token = this->peek_token(); - bool saw_comma = false; - bool closed_is_id = false; - if (token->is_identifier()) - { - Gogo* gogo = this->gogo_; - std::string recv_var = token->identifier(); - bool is_rv_exported = token->is_identifier_exported(); - Location recv_var_loc = token->location(); - token = this->advance_token(); - if (token->is_op(OPERATOR_COLONEQ)) - { - // case rv := <-c: - this->advance_token(); - Expression* e = this->expression(PRECEDENCE_NORMAL, false, false, - NULL, NULL); - Receive_expression* re = e->receive_expression(); - if (re == NULL) - { - if (!e->is_error_expression()) - error_at(this->location(), "expected receive expression"); - return false; - } - if (recv_var == "_") - { - error_at(recv_var_loc, - "no new variables on left side of %<:=%>"); - recv_var = "blank"; - } - *is_send = false; - *varname = gogo->pack_hidden_name(recv_var, is_rv_exported); - *channel = re->channel(); - return true; - } - else if (token->is_op(OPERATOR_COMMA)) - { - token = this->advance_token(); - if (token->is_identifier()) - { - std::string recv_closed = token->identifier(); - bool is_rc_exported = token->is_identifier_exported(); - Location recv_closed_loc = token->location(); - closed_is_id = true; - - token = this->advance_token(); - if (token->is_op(OPERATOR_COLONEQ)) - { - // case rv, rc := <-c: - this->advance_token(); - Expression* e = this->expression(PRECEDENCE_NORMAL, false, - false, NULL, NULL); - Receive_expression* re = e->receive_expression(); - if (re == NULL) - { - if (!e->is_error_expression()) - error_at(this->location(), - "expected receive expression"); - return false; - } - if (recv_var == "_" && recv_closed == "_") - { - error_at(recv_var_loc, - "no new variables on left side of %<:=%>"); - recv_var = "blank"; - } - *is_send = false; - if (recv_var != "_") - *varname = gogo->pack_hidden_name(recv_var, - is_rv_exported); - if (recv_closed != "_") - *closedname = gogo->pack_hidden_name(recv_closed, - is_rc_exported); - *channel = re->channel(); - return true; - } - - this->unget_token(Token::make_identifier_token(recv_closed, - is_rc_exported, - recv_closed_loc)); - } - - *val = this->id_to_expression(gogo->pack_hidden_name(recv_var, - is_rv_exported), - recv_var_loc); - saw_comma = true; - } - else - this->unget_token(Token::make_identifier_token(recv_var, - is_rv_exported, - recv_var_loc)); - } - - // If SAW_COMMA is false, then we are looking at the start of the - // send or receive expression. If SAW_COMMA is true, then *VAL is - // set and we just read a comma. - - Expression* e; - if (saw_comma || !this->peek_token()->is_op(OPERATOR_CHANOP)) - e = this->expression(PRECEDENCE_NORMAL, true, true, NULL, NULL); - else - { - // case <-c: - *is_send = false; - this->advance_token(); - *channel = this->expression(PRECEDENCE_NORMAL, false, true, NULL, NULL); - - // The next token should be ':'. If it is '<-', then we have - // case <-c <- v: - // which is to say, send on a channel received from a channel. - if (!this->peek_token()->is_op(OPERATOR_CHANOP)) - return true; - - e = Expression::make_receive(*channel, (*channel)->location()); - } - - if (this->peek_token()->is_op(OPERATOR_EQ)) - { - if (!this->advance_token()->is_op(OPERATOR_CHANOP)) - { - error_at(this->location(), "missing %<<-%>"); - return false; - } - *is_send = false; - this->advance_token(); - *channel = this->expression(PRECEDENCE_NORMAL, false, true, NULL, NULL); - if (saw_comma) - { - // case v, e = <-c: - // *VAL is already set. - if (!e->is_sink_expression()) - *closed = e; - } - else - { - // case v = <-c: - if (!e->is_sink_expression()) - *val = e; - } - return true; - } - - if (saw_comma) - { - if (closed_is_id) - error_at(this->location(), "expected %<=%> or %<:=%>"); - else - error_at(this->location(), "expected %<=%>"); - return false; - } - - if (this->peek_token()->is_op(OPERATOR_CHANOP)) - { - // case c <- v: - *is_send = true; - *channel = this->verify_not_sink(e); - this->advance_token(); - *val = this->expression(PRECEDENCE_NORMAL, false, true, NULL, NULL); - return true; - } - - error_at(this->location(), "expected %<<-%> or %<=%>"); - return false; -} - -// ForStat = "for" [ Condition | ForClause | RangeClause ] Block . -// Condition = Expression . - -void -Parse::for_stat(Label* label) -{ - go_assert(this->peek_token()->is_keyword(KEYWORD_FOR)); - Location location = this->location(); - const Token* token = this->advance_token(); - - // Open a block to hold any variables defined in the init statement - // of the for statement. - this->gogo_->start_block(location); - - Block* init = NULL; - Expression* cond = NULL; - Block* post = NULL; - Range_clause range_clause; - - if (!token->is_op(OPERATOR_LCURLY)) - { - if (token->is_keyword(KEYWORD_VAR)) - { - error_at(this->location(), - "var declaration not allowed in for initializer"); - this->var_decl(); - } - - if (token->is_op(OPERATOR_SEMICOLON)) - this->for_clause(&cond, &post); - else - { - // We might be looking at a Condition, an InitStat, or a - // RangeClause. - bool saw_send_stmt; - cond = this->simple_stat(false, &saw_send_stmt, &range_clause, NULL); - if (!this->peek_token()->is_op(OPERATOR_SEMICOLON)) - { - if (cond == NULL && !range_clause.found) - { - if (saw_send_stmt) - error_at(this->location(), - ("send statement used as value; " - "use select for non-blocking send")); - else - error_at(this->location(), "parse error in for statement"); - } - } - else - { - if (range_clause.found) - error_at(this->location(), "parse error after range clause"); - - if (cond != NULL) - { - // COND is actually an expression statement for - // InitStat at the start of a ForClause. - this->expression_stat(cond); - cond = NULL; - } - - this->for_clause(&cond, &post); - } - } - } - - // Build the For_statement and note that it is the current target - // for break and continue statements. - - For_statement* sfor; - For_range_statement* srange; - Statement* s; - if (!range_clause.found) - { - sfor = Statement::make_for_statement(init, cond, post, location); - s = sfor; - srange = NULL; - } - else - { - srange = Statement::make_for_range_statement(range_clause.index, - range_clause.value, - range_clause.range, - location); - s = srange; - sfor = NULL; - } - - this->push_break_statement(s, label); - this->push_continue_statement(s, label); - - // Gather the block of statements in the loop and add them to the - // For_statement. - - this->gogo_->start_block(this->location()); - Location end_loc = this->block(); - Block* statements = this->gogo_->finish_block(end_loc); - - if (sfor != NULL) - sfor->add_statements(statements); - else - srange->add_statements(statements); - - // This is no longer the break/continue target. - this->pop_break_statement(); - this->pop_continue_statement(); - - // Add the For_statement to the list of statements, and close out - // the block we started to hold any variables defined in the for - // statement. - - this->gogo_->add_statement(s); - - this->gogo_->add_block(this->gogo_->finish_block(this->location()), - location); -} - -// ForClause = [ InitStat ] ";" [ Condition ] ";" [ PostStat ] . -// InitStat = SimpleStat . -// PostStat = SimpleStat . - -// We have already read InitStat at this point. - -void -Parse::for_clause(Expression** cond, Block** post) -{ - go_assert(this->peek_token()->is_op(OPERATOR_SEMICOLON)); - this->advance_token(); - if (this->peek_token()->is_op(OPERATOR_SEMICOLON)) - *cond = NULL; - else if (this->peek_token()->is_op(OPERATOR_LCURLY)) - { - error_at(this->location(), - "unexpected semicolon or newline before %<{%>"); - *cond = NULL; - *post = NULL; - return; - } - else - *cond = this->expression(PRECEDENCE_NORMAL, false, true, NULL, NULL); - if (!this->peek_token()->is_op(OPERATOR_SEMICOLON)) - error_at(this->location(), "expected semicolon"); - else - this->advance_token(); - - if (this->peek_token()->is_op(OPERATOR_LCURLY)) - *post = NULL; - else - { - this->gogo_->start_block(this->location()); - this->simple_stat(false, NULL, NULL, NULL); - *post = this->gogo_->finish_block(this->location()); - } -} - -// RangeClause = IdentifierList ( "=" | ":=" ) "range" Expression . - -// This is the := version. It is called with a list of identifiers. - -void -Parse::range_clause_decl(const Typed_identifier_list* til, - Range_clause* p_range_clause) -{ - go_assert(this->peek_token()->is_keyword(KEYWORD_RANGE)); - Location location = this->location(); - - p_range_clause->found = true; - - go_assert(til->size() >= 1); - if (til->size() > 2) - error_at(this->location(), "too many variables for range clause"); - - this->advance_token(); - Expression* expr = this->expression(PRECEDENCE_NORMAL, false, false, NULL, - NULL); - p_range_clause->range = expr; - - bool any_new = false; - - const Typed_identifier* pti = &til->front(); - Named_object* no = this->init_var(*pti, NULL, expr, true, true, &any_new, - NULL, NULL); - if (any_new && no->is_variable()) - no->var_value()->set_type_from_range_index(); - p_range_clause->index = Expression::make_var_reference(no, location); - - if (til->size() == 1) - p_range_clause->value = NULL; - else - { - pti = &til->back(); - bool is_new = false; - no = this->init_var(*pti, NULL, expr, true, true, &is_new, NULL, NULL); - if (is_new && no->is_variable()) - no->var_value()->set_type_from_range_value(); - if (is_new) - any_new = true; - p_range_clause->value = Expression::make_var_reference(no, location); - } - - if (!any_new) - error_at(location, "variables redeclared but no variable is new"); -} - -// The = version of RangeClause. This is called with a list of -// expressions. - -void -Parse::range_clause_expr(const Expression_list* vals, - Range_clause* p_range_clause) -{ - go_assert(this->peek_token()->is_keyword(KEYWORD_RANGE)); - - p_range_clause->found = true; - - go_assert(vals->size() >= 1); - if (vals->size() > 2) - error_at(this->location(), "too many variables for range clause"); - - this->advance_token(); - p_range_clause->range = this->expression(PRECEDENCE_NORMAL, false, false, - NULL, NULL); - - p_range_clause->index = vals->front(); - if (vals->size() == 1) - p_range_clause->value = NULL; - else - p_range_clause->value = vals->back(); -} - -// Push a statement on the break stack. - -void -Parse::push_break_statement(Statement* enclosing, Label* label) -{ - if (this->break_stack_ == NULL) - this->break_stack_ = new Bc_stack(); - this->break_stack_->push_back(std::make_pair(enclosing, label)); -} - -// Push a statement on the continue stack. - -void -Parse::push_continue_statement(Statement* enclosing, Label* label) -{ - if (this->continue_stack_ == NULL) - this->continue_stack_ = new Bc_stack(); - this->continue_stack_->push_back(std::make_pair(enclosing, label)); -} - -// Pop the break stack. - -void -Parse::pop_break_statement() -{ - this->break_stack_->pop_back(); -} - -// Pop the continue stack. - -void -Parse::pop_continue_statement() -{ - this->continue_stack_->pop_back(); -} - -// Find a break or continue statement given a label name. - -Statement* -Parse::find_bc_statement(const Bc_stack* bc_stack, const std::string& label) -{ - if (bc_stack == NULL) - return NULL; - for (Bc_stack::const_reverse_iterator p = bc_stack->rbegin(); - p != bc_stack->rend(); - ++p) - { - if (p->second != NULL && p->second->name() == label) - { - p->second->set_is_used(); - return p->first; - } - } - return NULL; -} - -// BreakStat = "break" [ identifier ] . - -void -Parse::break_stat() -{ - go_assert(this->peek_token()->is_keyword(KEYWORD_BREAK)); - Location location = this->location(); - - const Token* token = this->advance_token(); - Statement* enclosing; - if (!token->is_identifier()) - { - if (this->break_stack_ == NULL || this->break_stack_->empty()) - { - error_at(this->location(), - "break statement not within for or switch or select"); - return; - } - enclosing = this->break_stack_->back().first; - } - else - { - enclosing = this->find_bc_statement(this->break_stack_, - token->identifier()); - if (enclosing == NULL) - { - // If there is a label with this name, mark it as used to - // avoid a useless error about an unused label. - this->gogo_->add_label_reference(token->identifier(), - Linemap::unknown_location(), false); - - error_at(token->location(), "invalid break label %qs", - Gogo::message_name(token->identifier()).c_str()); - this->advance_token(); - return; - } - this->advance_token(); - } - - Unnamed_label* label; - if (enclosing->classification() == Statement::STATEMENT_FOR) - label = enclosing->for_statement()->break_label(); - else if (enclosing->classification() == Statement::STATEMENT_FOR_RANGE) - label = enclosing->for_range_statement()->break_label(); - else if (enclosing->classification() == Statement::STATEMENT_SWITCH) - label = enclosing->switch_statement()->break_label(); - else if (enclosing->classification() == Statement::STATEMENT_TYPE_SWITCH) - label = enclosing->type_switch_statement()->break_label(); - else if (enclosing->classification() == Statement::STATEMENT_SELECT) - label = enclosing->select_statement()->break_label(); - else - go_unreachable(); - - this->gogo_->add_statement(Statement::make_break_statement(label, - location)); -} - -// ContinueStat = "continue" [ identifier ] . - -void -Parse::continue_stat() -{ - go_assert(this->peek_token()->is_keyword(KEYWORD_CONTINUE)); - Location location = this->location(); - - const Token* token = this->advance_token(); - Statement* enclosing; - if (!token->is_identifier()) - { - if (this->continue_stack_ == NULL || this->continue_stack_->empty()) - { - error_at(this->location(), "continue statement not within for"); - return; - } - enclosing = this->continue_stack_->back().first; - } - else - { - enclosing = this->find_bc_statement(this->continue_stack_, - token->identifier()); - if (enclosing == NULL) - { - // If there is a label with this name, mark it as used to - // avoid a useless error about an unused label. - this->gogo_->add_label_reference(token->identifier(), - Linemap::unknown_location(), false); - - error_at(token->location(), "invalid continue label %qs", - Gogo::message_name(token->identifier()).c_str()); - this->advance_token(); - return; - } - this->advance_token(); - } - - Unnamed_label* label; - if (enclosing->classification() == Statement::STATEMENT_FOR) - label = enclosing->for_statement()->continue_label(); - else if (enclosing->classification() == Statement::STATEMENT_FOR_RANGE) - label = enclosing->for_range_statement()->continue_label(); - else - go_unreachable(); - - this->gogo_->add_statement(Statement::make_continue_statement(label, - location)); -} - -// GotoStat = "goto" identifier . - -void -Parse::goto_stat() -{ - go_assert(this->peek_token()->is_keyword(KEYWORD_GOTO)); - Location location = this->location(); - const Token* token = this->advance_token(); - if (!token->is_identifier()) - error_at(this->location(), "expected label for goto"); - else - { - Label* label = this->gogo_->add_label_reference(token->identifier(), - location, true); - Statement* s = Statement::make_goto_statement(label, location); - this->gogo_->add_statement(s); - this->advance_token(); - } -} - -// PackageClause = "package" PackageName . - -void -Parse::package_clause() -{ - const Token* token = this->peek_token(); - Location location = token->location(); - std::string name; - if (!token->is_keyword(KEYWORD_PACKAGE)) - { - error_at(this->location(), "program must start with package clause"); - name = "ERROR"; - } - else - { - token = this->advance_token(); - if (token->is_identifier()) - { - name = token->identifier(); - if (name == "_") - { - error_at(this->location(), "invalid package name _"); - name = "blank"; - } - this->advance_token(); - } - else - { - error_at(this->location(), "package name must be an identifier"); - name = "ERROR"; - } - } - this->gogo_->set_package_name(name, location); -} - -// ImportDecl = "import" Decl<ImportSpec> . - -void -Parse::import_decl() -{ - go_assert(this->peek_token()->is_keyword(KEYWORD_IMPORT)); - this->advance_token(); - this->decl(&Parse::import_spec, NULL); -} - -// ImportSpec = [ "." | PackageName ] PackageFileName . - -void -Parse::import_spec(void*) -{ - const Token* token = this->peek_token(); - Location location = token->location(); - - std::string local_name; - bool is_local_name_exported = false; - if (token->is_op(OPERATOR_DOT)) - { - local_name = "."; - token = this->advance_token(); - } - else if (token->is_identifier()) - { - local_name = token->identifier(); - is_local_name_exported = token->is_identifier_exported(); - token = this->advance_token(); - } - - if (!token->is_string()) - { - error_at(this->location(), "import statement not a string"); - this->advance_token(); - return; - } - - this->gogo_->import_package(token->string_value(), local_name, - is_local_name_exported, location); - - this->advance_token(); -} - -// SourceFile = PackageClause ";" { ImportDecl ";" } -// { TopLevelDecl ";" } . - -void -Parse::program() -{ - this->package_clause(); - - const Token* token = this->peek_token(); - if (token->is_op(OPERATOR_SEMICOLON)) - token = this->advance_token(); - else - error_at(this->location(), - "expected %<;%> or newline after package clause"); - - while (token->is_keyword(KEYWORD_IMPORT)) - { - this->import_decl(); - token = this->peek_token(); - if (token->is_op(OPERATOR_SEMICOLON)) - token = this->advance_token(); - else - error_at(this->location(), - "expected %<;%> or newline after import declaration"); - } - - while (!token->is_eof()) - { - if (this->declaration_may_start_here()) - this->declaration(); - else - { - error_at(this->location(), "expected declaration"); - this->gogo_->mark_locals_used(); - do - this->advance_token(); - while (!this->peek_token()->is_eof() - && !this->peek_token()->is_op(OPERATOR_SEMICOLON) - && !this->peek_token()->is_op(OPERATOR_RCURLY)); - if (!this->peek_token()->is_eof() - && !this->peek_token()->is_op(OPERATOR_SEMICOLON)) - this->advance_token(); - } - token = this->peek_token(); - if (token->is_op(OPERATOR_SEMICOLON)) - token = this->advance_token(); - else if (!token->is_eof() || !saw_errors()) - { - if (token->is_op(OPERATOR_CHANOP)) - error_at(this->location(), - ("send statement used as value; " - "use select for non-blocking send")); - else - error_at(this->location(), - "expected %<;%> or newline after top level declaration"); - this->skip_past_error(OPERATOR_INVALID); - } - } -} - -// Reset the current iota value. - -void -Parse::reset_iota() -{ - this->iota_ = 0; -} - -// Return the current iota value. - -int -Parse::iota_value() -{ - return this->iota_; -} - -// Increment the current iota value. - -void -Parse::increment_iota() -{ - ++this->iota_; -} - -// Skip forward to a semicolon or OP. OP will normally be -// OPERATOR_RPAREN or OPERATOR_RCURLY. If we find a semicolon, move -// past it and return. If we find OP, it will be the next token to -// read. Return true if we are OK, false if we found EOF. - -bool -Parse::skip_past_error(Operator op) -{ - this->gogo_->mark_locals_used(); - const Token* token = this->peek_token(); - while (!token->is_op(op)) - { - if (token->is_eof()) - return false; - if (token->is_op(OPERATOR_SEMICOLON)) - { - this->advance_token(); - return true; - } - token = this->advance_token(); - } - return true; -} - -// Check that an expression is not a sink. - -Expression* -Parse::verify_not_sink(Expression* expr) -{ - if (expr->is_sink_expression()) - { - error_at(expr->location(), "cannot use _ as value"); - expr = Expression::make_error(expr->location()); - } - return expr; -} - -// Mark a variable as used. - -void -Parse::mark_var_used(Named_object* no) -{ - if (no->is_variable()) - { - no->var_value()->set_is_used(); - - // When a type switch uses := to define a variable, then for - // each case with a single type we introduce a new variable with - // the appropriate type. When we do, if the newly introduced - // variable is used, then the type switch variable is used. - Type_switch_vars::iterator p = this->type_switch_vars_.find(no); - if (p != this->type_switch_vars_.end()) - p->second->var_value()->set_is_used(); - } -} diff --git a/gcc-4.8.1/gcc/go/gofrontend/parse.h b/gcc-4.8.1/gcc/go/gofrontend/parse.h deleted file mode 100644 index 99e0eeebc..000000000 --- a/gcc-4.8.1/gcc/go/gofrontend/parse.h +++ /dev/null @@ -1,335 +0,0 @@ -// parse.h -- Go frontend parser. -*- C++ -*- - -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#ifndef GO_PARSE_H -#define GO_PARSE_H - -class Set_iota_traverse; -class Lex; -class Gogo; -class Named_object; -class Type; -class Typed_identifier; -class Typed_identifier_list; -class Channel_type; -class Function_type; -class Block; -class Expression; -class Expression_list; -class Struct_field_list; -class Case_clauses; -class Type_case_clauses; -class Select_clauses; -class Statement; -class Label; - -// Parse the program. - -class Parse -{ - public: - Parse(Lex*, Gogo*); - - // Parse a program. - void - program(); - - private: - // Precedence values. - enum Precedence - { - PRECEDENCE_INVALID = -1, - PRECEDENCE_NORMAL = 0, - PRECEDENCE_OROR, - PRECEDENCE_ANDAND, - PRECEDENCE_RELOP, - PRECEDENCE_ADDOP, - PRECEDENCE_MULOP - }; - - // We use this when parsing the range clause of a for statement. - struct Range_clause - { - // Set to true if we found a range clause. - bool found; - // The index expression. - Expression* index; - // The value expression. - Expression* value; - // The range expression. - Expression* range; - - Range_clause() - : found(false), index(NULL), value(NULL), range(NULL) - { } - }; - - // We use this when parsing the statement at the start of a switch, - // in order to recognize type switches. - struct Type_switch - { - // Set to true if we find a type switch. - bool found; - // The variable name. - std::string name; - // The location of the variable. - Location location; - // The expression. - Expression* expr; - - Type_switch() - : found(false), name(), location(UNKNOWN_LOCATION), expr(NULL) - { } - }; - - // A variable defined in an enclosing function referenced by the - // current function. - class Enclosing_var - { - public: - Enclosing_var(Named_object* var, Named_object* in_function, - unsigned int index) - : var_(var), in_function_(in_function), index_(index) - { } - - // We put these in a vector, so we need a default constructor. - Enclosing_var() - : var_(NULL), in_function_(NULL), index_(-1U) - { } - - Named_object* - var() const - { return this->var_; } - - Named_object* - in_function() const - { return this->in_function_; } - - unsigned int - index() const - { return this->index_; } - - private: - // The variable which is being referred to. - Named_object* var_; - // The function where the variable is defined. - Named_object* in_function_; - // The index of the field in this function's closure struct for - // this variable. - unsigned int index_; - }; - - // We store Enclosing_var entries in a set, so we need a comparator. - struct Enclosing_var_comparison - { - bool - operator()(const Enclosing_var&, const Enclosing_var&); - }; - - // A set of Enclosing_var entries. - typedef std::set<Enclosing_var, Enclosing_var_comparison> Enclosing_vars; - - // Used to detect duplicate parameter/result names. - typedef std::map<std::string, const Typed_identifier*> Names; - - // Peek at the current token from the lexer. - const Token* - peek_token(); - - // Consume the current token, return the next one. - const Token* - advance_token(); - - // Push a token back on the input stream. - void - unget_token(const Token&); - - // The location of the current token. - Location - location(); - - // For break and continue we keep a stack of statements with - // associated labels (if any). The top of the stack is used for a - // break or continue statement with no label. - typedef std::vector<std::pair<Statement*, Label*> > Bc_stack; - - // Map from type switch variables to the variables they mask, so - // that a use of the type switch variable can become a use of the - // real variable. - typedef Unordered_map(Named_object*, Named_object*) Type_switch_vars; - - // Parser nonterminals. - void identifier_list(Typed_identifier_list*); - Expression_list* expression_list(Expression*, bool may_be_sink, - bool may_be_composite_lit); - bool qualified_ident(std::string*, Named_object**); - Type* type(); - bool type_may_start_here(); - Type* type_name(bool issue_error); - Type* array_type(bool may_use_ellipsis); - Type* map_type(); - Type* struct_type(); - void field_decl(Struct_field_list*); - Type* pointer_type(); - Type* channel_type(); - void check_signature_names(const Typed_identifier_list*, Names*); - Function_type* signature(Typed_identifier*, Location); - bool parameters(Typed_identifier_list**, bool* is_varargs); - Typed_identifier_list* parameter_list(bool* is_varargs); - void parameter_decl(bool, Typed_identifier_list*, bool*, bool*); - bool result(Typed_identifier_list**); - Location block(); - Type* interface_type(); - void method_spec(Typed_identifier_list*); - void declaration(); - bool declaration_may_start_here(); - void decl(void (Parse::*)(void*), void*); - void list(void (Parse::*)(void*), void*, bool); - void const_decl(); - void const_spec(Type**, Expression_list**); - void type_decl(); - void type_spec(void*); - void var_decl(); - void var_spec(void*); - void init_vars(const Typed_identifier_list*, Type*, Expression_list*, - bool is_coloneq, Location); - bool init_vars_from_call(const Typed_identifier_list*, Type*, Expression*, - bool is_coloneq, Location); - bool init_vars_from_map(const Typed_identifier_list*, Type*, Expression*, - bool is_coloneq, Location); - bool init_vars_from_receive(const Typed_identifier_list*, Type*, - Expression*, bool is_coloneq, Location); - bool init_vars_from_type_guard(const Typed_identifier_list*, Type*, - Expression*, bool is_coloneq, - Location); - Named_object* init_var(const Typed_identifier&, Type*, Expression*, - bool is_coloneq, bool type_from_init, bool* is_new, - Expression_list* vars, Expression_list* vals); - Named_object* create_dummy_global(Type*, Expression*, Location); - void finish_init_vars(Expression_list* vars, Expression_list* vals, - Location); - void simple_var_decl_or_assignment(const std::string&, Location, - bool may_be_composite_lit, - Range_clause*, Type_switch*); - void function_decl(bool saw_nointerface); - Typed_identifier* receiver(); - Expression* operand(bool may_be_sink, bool *is_parenthesized); - Expression* enclosing_var_reference(Named_object*, Named_object*, - Location); - Expression* composite_lit(Type*, int depth, Location); - Expression* function_lit(); - Expression* create_closure(Named_object* function, Enclosing_vars*, - Location); - Expression* primary_expr(bool may_be_sink, bool may_be_composite_lit, - bool* is_type_switch, bool* is_parenthesized); - Expression* selector(Expression*, bool* is_type_switch); - Expression* index(Expression*); - Expression* call(Expression*); - Expression* expression(Precedence, bool may_be_sink, - bool may_be_composite_lit, bool* is_type_switch, - bool *is_parenthesized); - bool expression_may_start_here(); - Expression* unary_expr(bool may_be_sink, bool may_be_composite_lit, - bool* is_type_switch, bool* is_parenthesized); - Type* reassociate_chan_direction(Channel_type*, Location); - Expression* qualified_expr(Expression*, Location); - Expression* id_to_expression(const std::string&, Location); - void statement(Label*); - bool statement_may_start_here(); - void labeled_stmt(const std::string&, Location); - Expression* simple_stat(bool, bool*, Range_clause*, Type_switch*); - bool simple_stat_may_start_here(); - void statement_list(); - bool statement_list_may_start_here(); - void expression_stat(Expression*); - void send_stmt(Expression*); - void inc_dec_stat(Expression*); - void assignment(Expression*, bool may_be_composite_lit, Range_clause*); - void tuple_assignment(Expression_list*, bool may_be_composite_lit, - Range_clause*); - void send(); - void go_or_defer_stat(); - void return_stat(); - void if_stat(); - void switch_stat(Label*); - Statement* expr_switch_body(Label*, Expression*, Location); - void expr_case_clause(Case_clauses*, bool* saw_default); - Expression_list* expr_switch_case(bool*); - Statement* type_switch_body(Label*, const Type_switch&, Location); - void type_case_clause(Named_object*, Type_case_clauses*, bool* saw_default); - void type_switch_case(std::vector<Type*>*, bool*); - void select_stat(Label*); - void comm_clause(Select_clauses*, bool* saw_default); - bool comm_case(bool*, Expression**, Expression**, Expression**, - std::string*, std::string*, bool*); - bool send_or_recv_stmt(bool*, Expression**, Expression**, Expression**, - std::string*, std::string*); - void for_stat(Label*); - void for_clause(Expression**, Block**); - void range_clause_decl(const Typed_identifier_list*, Range_clause*); - void range_clause_expr(const Expression_list*, Range_clause*); - void push_break_statement(Statement*, Label*); - void push_continue_statement(Statement*, Label*); - void pop_break_statement(); - void pop_continue_statement(); - Statement* find_bc_statement(const Bc_stack*, const std::string&); - void break_stat(); - void continue_stat(); - void goto_stat(); - void package_clause(); - void import_decl(); - void import_spec(void*); - - void reset_iota(); - int iota_value(); - void increment_iota(); - - // Skip past an error looking for a semicolon or OP. Return true if - // all is well, false if we found EOF. - bool - skip_past_error(Operator op); - - // Verify that an expression is not a sink, and return either the - // expression or an error. - Expression* - verify_not_sink(Expression*); - - // Return the statement associated with a label in a Bc_stack, or - // NULL. - Statement* - find_bc_statement(const Bc_stack*, const std::string&) const; - - // Mark a variable as used. - void - mark_var_used(Named_object*); - - // The lexer output we are parsing. - Lex* lex_; - // The current token. - Token token_; - // A token pushed back on the input stream. - Token unget_token_; - // Whether unget_token_ is valid. - bool unget_token_valid_; - // Whether the function we are parsing had errors in the signature. - bool is_erroneous_function_; - // The code we are generating. - Gogo* gogo_; - // A stack of statements for which break may be used. - Bc_stack* break_stack_; - // A stack of statements for which continue may be used. - Bc_stack* continue_stack_; - // The current iota value. - int iota_; - // References from the local function to variables defined in - // enclosing functions. - Enclosing_vars enclosing_vars_; - // Map from type switch variables to real variables. - Type_switch_vars type_switch_vars_; -}; - - -#endif // !defined(GO_PARSE_H) diff --git a/gcc-4.8.1/gcc/go/gofrontend/runtime.cc b/gcc-4.8.1/gcc/go/gofrontend/runtime.cc deleted file mode 100644 index ecc508d0d..000000000 --- a/gcc-4.8.1/gcc/go/gofrontend/runtime.cc +++ /dev/null @@ -1,402 +0,0 @@ -// runtime.cc -- runtime functions called by generated code - -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "go-system.h" - -#include "gogo.h" -#include "types.h" -#include "expressions.h" -#include "runtime.h" - -// The frontend generates calls to various runtime functions. They -// are implemented in libgo/runtime. This is how the runtime -// functions are represented in the frontend. Note that there is -// currently nothing which ensures that the compiler's understanding -// of the runtime function matches the actual implementation in -// libgo/runtime. - -// Parameter and result types used by runtime functions. - -enum Runtime_function_type -{ - // General indicator that value is not used. - RFT_VOID, - // Go type bool, C type _Bool. - RFT_BOOL, - // Go type *bool, C type _Bool*. - RFT_BOOLPTR, - // Go type int, C type intgo. - RFT_INT, - // Go type int32, C type int32_t. - RFT_INT32, - // Go type int64, C type int64_t. - RFT_INT64, - // Go type uint64, C type uint64_t. - RFT_UINT64, - // Go type uintptr, C type uintptr_t. - RFT_UINTPTR, - // Go type rune, C type int32_t. - RFT_RUNE, - // Go type float64, C type double. - RFT_FLOAT64, - // Go type complex128, C type __complex double. - RFT_COMPLEX128, - // Go type string, C type struct __go_string. - RFT_STRING, - // Go type unsafe.Pointer, C type "void *". - RFT_POINTER, - // Go type []any, C type struct __go_open_array. - RFT_SLICE, - // Go type map[any]any, C type struct __go_map *. - RFT_MAP, - // Pointer to map iteration type. - RFT_MAPITER, - // Go type chan any, C type struct __go_channel *. - RFT_CHAN, - // Go type non-empty interface, C type struct __go_interface. - RFT_IFACE, - // Go type interface{}, C type struct __go_empty_interface. - RFT_EFACE, - // Go type func(unsafe.Pointer), C type void (*) (void *). - RFT_FUNC_PTR, - // Pointer to Go type descriptor. - RFT_TYPE, - // Pointer to map descriptor. - RFT_MAPDESCRIPTOR, - - NUMBER_OF_RUNTIME_FUNCTION_TYPES -}; - -// The Type structures for the runtime function types. - -static Type* runtime_function_types[NUMBER_OF_RUNTIME_FUNCTION_TYPES]; - -// Get the Type for a Runtime_function_type code. - -static Type* -runtime_function_type(Runtime_function_type bft) -{ - go_assert(bft < NUMBER_OF_RUNTIME_FUNCTION_TYPES); - if (runtime_function_types[bft] == NULL) - { - const Location bloc = Linemap::predeclared_location(); - Type* t; - switch (bft) - { - default: - case RFT_VOID: - go_unreachable(); - - case RFT_BOOL: - t = Type::lookup_bool_type(); - break; - - case RFT_BOOLPTR: - t = Type::make_pointer_type(Type::lookup_bool_type()); - break; - - case RFT_INT: - t = Type::lookup_integer_type("int"); - break; - - case RFT_INT32: - t = Type::lookup_integer_type("int32"); - break; - - case RFT_INT64: - t = Type::lookup_integer_type("int64"); - break; - - case RFT_UINT64: - t = Type::lookup_integer_type("uint64"); - break; - - case RFT_RUNE: - t = Type::lookup_integer_type("int32"); - break; - - case RFT_UINTPTR: - t = Type::lookup_integer_type("uintptr"); - break; - - case RFT_FLOAT64: - t = Type::lookup_float_type("float64"); - break; - - case RFT_COMPLEX128: - t = Type::lookup_complex_type("complex128"); - break; - - case RFT_STRING: - t = Type::lookup_string_type(); - break; - - case RFT_POINTER: - t = Type::make_pointer_type(Type::make_void_type()); - break; - - case RFT_SLICE: - t = Type::make_array_type(Type::make_void_type(), NULL); - break; - - case RFT_MAP: - t = Type::make_map_type(Type::make_void_type(), - Type::make_void_type(), - bloc); - break; - - case RFT_MAPITER: - t = Type::make_pointer_type(Runtime::map_iteration_type()); - break; - - case RFT_CHAN: - t = Type::make_channel_type(true, true, Type::make_void_type()); - break; - - case RFT_IFACE: - { - Typed_identifier_list* methods = new Typed_identifier_list(); - Type* mtype = Type::make_function_type(NULL, NULL, NULL, bloc); - methods->push_back(Typed_identifier("x", mtype, bloc)); - Interface_type* it = Type::make_interface_type(methods, bloc); - it->finalize_methods(); - t = it; - } - break; - - case RFT_EFACE: - t = Type::make_empty_interface_type(bloc); - break; - - case RFT_FUNC_PTR: - { - Typed_identifier_list* param_types = new Typed_identifier_list(); - Type* ptrtype = runtime_function_type(RFT_POINTER); - param_types->push_back(Typed_identifier("", ptrtype, bloc)); - t = Type::make_function_type(NULL, param_types, NULL, bloc); - } - break; - - case RFT_TYPE: - t = Type::make_type_descriptor_ptr_type(); - break; - - case RFT_MAPDESCRIPTOR: - t = Type::make_pointer_type(Map_type::make_map_descriptor_type()); - break; - } - - runtime_function_types[bft] = t; - } - - return runtime_function_types[bft]; -} - -// Convert an expression to the type to pass to a runtime function. - -static Expression* -convert_to_runtime_function_type(Runtime_function_type bft, Expression* e, - Location loc) -{ - switch (bft) - { - default: - case RFT_VOID: - go_unreachable(); - - case RFT_BOOL: - case RFT_BOOLPTR: - case RFT_INT: - case RFT_INT32: - case RFT_INT64: - case RFT_UINT64: - case RFT_UINTPTR: - case RFT_RUNE: - case RFT_FLOAT64: - case RFT_COMPLEX128: - case RFT_STRING: - case RFT_POINTER: - case RFT_MAPITER: - case RFT_FUNC_PTR: - { - Type* t = runtime_function_type(bft); - if (!Type::are_identical(t, e->type(), true, NULL)) - e = Expression::make_cast(t, e, loc); - return e; - } - - case RFT_SLICE: - case RFT_MAP: - case RFT_CHAN: - case RFT_IFACE: - case RFT_EFACE: - return Expression::make_unsafe_cast(runtime_function_type(bft), e, loc); - - case RFT_TYPE: - go_assert(e->type() == Type::make_type_descriptor_ptr_type()); - return e; - - case RFT_MAPDESCRIPTOR: - go_assert(e->type()->points_to() - == Map_type::make_map_descriptor_type()); - return e; - } -} - -// Convert all the types used for runtime functions to the backend -// representation. - -void -Runtime::convert_types(Gogo* gogo) -{ - for (int i = 0; i < static_cast<int>(NUMBER_OF_RUNTIME_FUNCTION_TYPES); ++i) - { - Type* t = runtime_function_types[i]; - if (t != NULL && t->named_type() != NULL) - { - bool r = t->verify(); - go_assert(r); - t->named_type()->convert(gogo); - } - } -} - -// The type used to define a runtime function. - -struct Runtime_function -{ - // Function name. - const char* name; - // Parameter types. Never more than 6, as it happens. RFT_VOID if - // not used. - Runtime_function_type parameter_types[6]; - // Result types. Never more than 2, as it happens. RFT_VOID if not - // used. - Runtime_function_type result_types[2]; -}; - -static const Runtime_function runtime_functions[] = -{ - -#define DEF_GO_RUNTIME(CODE, NAME, PARAMS, RESULTS) { NAME, PARAMS, RESULTS } , - -#include "runtime.def" - -#undef DEF_GO_RUNTIME - -}; - -static Named_object* -runtime_function_declarations[Runtime::NUMBER_OF_FUNCTIONS]; - -// Get the declaration of a runtime function. - -Named_object* -Runtime::runtime_declaration(Function code) -{ - go_assert(code < Runtime::NUMBER_OF_FUNCTIONS); - if (runtime_function_declarations[code] == NULL) - { - const Runtime_function* pb = &runtime_functions[code]; - - Location bloc = Linemap::predeclared_location(); - - Typed_identifier_list* param_types = NULL; - if (pb->parameter_types[0] != RFT_VOID) - { - param_types = new Typed_identifier_list(); - for (unsigned int i = 0; - i < (sizeof(pb->parameter_types) - / sizeof (pb->parameter_types[0])); - i++) - { - if (pb->parameter_types[i] == RFT_VOID) - break; - Type* t = runtime_function_type(pb->parameter_types[i]); - param_types->push_back(Typed_identifier("", t, bloc)); - } - } - - Typed_identifier_list* result_types = NULL; - if (pb->result_types[0] != RFT_VOID) - { - result_types = new Typed_identifier_list(); - for (unsigned int i = 0; - i < sizeof(pb->result_types) / sizeof(pb->result_types[0]); - i++) - { - if (pb->result_types[i] == RFT_VOID) - break; - Type* t = runtime_function_type(pb->result_types[i]); - result_types->push_back(Typed_identifier("", t, bloc)); - } - } - - Function_type* fntype = Type::make_function_type(NULL, param_types, - result_types, bloc); - const char* n = pb->name; - const char* n1 = strchr(n, '.'); - if (n1 != NULL) - n = n1 + 1; - Named_object* no = Named_object::make_function_declaration(n, NULL, - fntype, bloc); - no->func_declaration_value()->set_asm_name(pb->name); - - runtime_function_declarations[code] = no; - } - - return runtime_function_declarations[code]; -} - -// Make a call to a runtime function. - -Call_expression* -Runtime::make_call(Runtime::Function code, Location loc, - int param_count, ...) -{ - go_assert(code < Runtime::NUMBER_OF_FUNCTIONS); - - const Runtime_function* pb = &runtime_functions[code]; - - go_assert(static_cast<size_t>(param_count) - <= sizeof(pb->parameter_types) / sizeof(pb->parameter_types[0])); - - Named_object* no = runtime_declaration(code); - Expression* func = Expression::make_func_reference(no, NULL, loc); - - Expression_list* args = new Expression_list(); - args->reserve(param_count); - - va_list ap; - va_start(ap, param_count); - for (int i = 0; i < param_count; ++i) - { - Expression* e = va_arg(ap, Expression*); - Runtime_function_type rft = pb->parameter_types[i]; - args->push_back(convert_to_runtime_function_type(rft, e, loc)); - } - va_end(ap); - - return Expression::make_call(func, args, false, loc); -} - -// The type we use for a map iteration. This is really a struct which -// is four pointers long. This must match the runtime struct -// __go_hash_iter. - -Type* -Runtime::map_iteration_type() -{ - const unsigned long map_iteration_size = 4; - - mpz_t ival; - mpz_init_set_ui(ival, map_iteration_size); - Expression* iexpr = Expression::make_integer(&ival, NULL, - Linemap::predeclared_location()); - mpz_clear(ival); - - return Type::make_array_type(runtime_function_type(RFT_POINTER), iexpr); -} diff --git a/gcc-4.8.1/gcc/go/gofrontend/runtime.def b/gcc-4.8.1/gcc/go/gofrontend/runtime.def deleted file mode 100644 index 0d9ff0380..000000000 --- a/gcc-4.8.1/gcc/go/gofrontend/runtime.def +++ /dev/null @@ -1,373 +0,0 @@ -// runtime.def -- runtime functions called by generated code. -*- C++ -*- - -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Definitions for the Go runtime functions. - -// Parameter type helper macros. -#define ABFT6(T1, T2, T3, T4, T5, T6) \ - { RFT_ ## T1, RFT_ ## T2, RFT_ ## T3, RFT_ ## T4, RFT_ ## T5, RFT_ ## T6 } -#define P0() ABFT6(VOID, VOID, VOID, VOID, VOID, VOID) -#define P1(T) ABFT6(T, VOID, VOID, VOID, VOID, VOID) -#define P2(T1, T2) ABFT6(T1, T2, VOID, VOID, VOID, VOID) -#define P3(T1, T2, T3) ABFT6(T1, T2, T3, VOID, VOID, VOID) -#define P4(T1, T2, T3, T4) ABFT6(T1, T2, T3, T4, VOID, VOID) -#define P5(T1, T2, T3, T4, T5) ABFT6(T1, T2, T3, T4, T5, VOID) -#define P6(T1,T2,T3,T4,T5,T6) ABFT6(T1, T2, T3, T4, T5, T6) - -// Result type helper macros. -#define ABFT2(T1, T2) { RFT_ ## T1, RFT_ ## T2 } -#define R0() ABFT2(VOID, VOID) -#define R1(T) ABFT2(T, VOID) -#define R2(T1, T2) ABFT2(T1, T2) - -// Define all the Go runtime functions. The first parameter is the -// enum code used to refer to the function. The second parameter is -// the name. The third is the parameter types and the fourth is the -// result types. - -// The standard C memcmp function, used for struct comparisons. -DEF_GO_RUNTIME(MEMCMP, "__go_memcmp", P3(POINTER, POINTER, UINTPTR), R1(INT)) - -// Range over a string, returning the next index. -DEF_GO_RUNTIME(STRINGITER, "runtime.stringiter", P2(STRING, INT), R1(INT)) - -// Range over a string, returning the next index and character. -DEF_GO_RUNTIME(STRINGITER2, "runtime.stringiter2", P2(STRING, INT), - R2(INT, RUNE)) - -// Concatenate two strings. -DEF_GO_RUNTIME(STRING_PLUS, "__go_string_plus", P2(STRING, STRING), R1(STRING)) - -// Compare two strings. -DEF_GO_RUNTIME(STRCMP, "__go_strcmp", P2(STRING, STRING), R1(INT)) - -// Take a slice of a string. -DEF_GO_RUNTIME(STRING_SLICE, "__go_string_slice", P3(STRING, INT, INT), - R1(STRING)) - -// Convert an integer to a string. -DEF_GO_RUNTIME(INT_TO_STRING, "__go_int_to_string", P1(INT), R1(STRING)) - -// Convert a byte array to a string. -DEF_GO_RUNTIME(BYTE_ARRAY_TO_STRING, "__go_byte_array_to_string", - P2(POINTER, INT), R1(STRING)) - -// Convert an int array to a string. -DEF_GO_RUNTIME(INT_ARRAY_TO_STRING, "__go_int_array_to_string", - P2(POINTER, INT), R1(STRING)) - -// Convert a string to a byte slice. -DEF_GO_RUNTIME(STRING_TO_BYTE_ARRAY, "__go_string_to_byte_array", - P1(STRING), R1(SLICE)) - -// Convert a string to an int slice. -DEF_GO_RUNTIME(STRING_TO_INT_ARRAY, "__go_string_to_int_array", - P1(STRING), R1(SLICE)) - - -// Make a slice. -DEF_GO_RUNTIME(MAKESLICE1, "__go_make_slice1", P2(TYPE, UINTPTR), R1(SLICE)) -DEF_GO_RUNTIME(MAKESLICE2, "__go_make_slice2", P3(TYPE, UINTPTR, UINTPTR), - R1(SLICE)) -DEF_GO_RUNTIME(MAKESLICE1BIG, "__go_make_slice1_big", P2(TYPE, UINT64), - R1(SLICE)) -DEF_GO_RUNTIME(MAKESLICE2BIG, "__go_make_slice2_big", P3(TYPE, UINT64, UINT64), - R1(SLICE)) - - -// Make a map. -DEF_GO_RUNTIME(MAKEMAP, "__go_new_map", P2(MAPDESCRIPTOR, UINTPTR), R1(MAP)) -DEF_GO_RUNTIME(MAKEMAPBIG, "__go_new_map_big", P2(MAPDESCRIPTOR, UINT64), - R1(MAP)) - -// Build a map from a composite literal. -DEF_GO_RUNTIME(CONSTRUCT_MAP, "__go_construct_map", - P6(POINTER, UINTPTR, UINTPTR, UINTPTR, UINTPTR, POINTER), - R1(MAP)) - -// Get the length of a map (the number of entries). -DEF_GO_RUNTIME(MAP_LEN, "__go_map_len", P1(MAP), R1(INT)) - -// Look up a key in a map. -DEF_GO_RUNTIME(MAP_INDEX, "__go_map_index", P3(MAP, POINTER, BOOL), - R1(POINTER)) - -// Look up a key in a map returning whether it is present. -DEF_GO_RUNTIME(MAPACCESS2, "runtime.mapaccess2", - P4(TYPE, MAP, POINTER, POINTER), R1(BOOL)) - -// Tuple assignment to a map element. -DEF_GO_RUNTIME(MAPASSIGN2, "runtime.mapassign2", - P4(MAP, POINTER, POINTER, BOOL), R0()) - -// Delete a key from a map. -DEF_GO_RUNTIME(MAPDELETE, "runtime.mapdelete", P2(MAP, POINTER), R0()) - -// Begin a range over a map. -DEF_GO_RUNTIME(MAPITERINIT, "runtime.mapiterinit", P2(MAP, MAPITER), R0()) - -// Range over a map, returning the next key. -DEF_GO_RUNTIME(MAPITER1, "runtime.mapiter1", P2(MAPITER, POINTER), R0()) - -// Range over a map, returning the next key and value. -DEF_GO_RUNTIME(MAPITER2, "runtime.mapiter2", P3(MAPITER, POINTER, POINTER), - R0()) - -// Range over a map, moving to the next map entry. -DEF_GO_RUNTIME(MAPITERNEXT, "runtime.mapiternext", P1(MAPITER), R0()) - - -// Make a channel. -DEF_GO_RUNTIME(MAKECHAN, "__go_new_channel", P2(TYPE, UINTPTR), R1(CHAN)) -DEF_GO_RUNTIME(MAKECHANBIG, "__go_new_channel_big", P2(TYPE, UINT64), R1(CHAN)) - -// Get the length of a channel (the number of unread values). -DEF_GO_RUNTIME(CHAN_LEN, "__go_chan_len", P1(CHAN), R1(INT)) - -// Get the capacity of a channel (the size of the buffer). -DEF_GO_RUNTIME(CHAN_CAP, "__go_chan_cap", P1(CHAN), R1(INT)) - -// Send a small value on a channel. -DEF_GO_RUNTIME(SEND_SMALL, "__go_send_small", P3(TYPE, CHAN, UINT64), R0()) - -// Send a big value on a channel. -DEF_GO_RUNTIME(SEND_BIG, "__go_send_big", P3(TYPE, CHAN, POINTER), R0()) - -// Receive a small value from a channel. -DEF_GO_RUNTIME(RECEIVE_SMALL, "__go_receive_small", P2(TYPE, CHAN), R1(UINT64)) - -// Receive a big value from a channel. -DEF_GO_RUNTIME(RECEIVE_BIG, "__go_receive_big", P3(TYPE, CHAN, POINTER), R0()) - -// Receive a value from a channel returning whether it is closed. -DEF_GO_RUNTIME(CHANRECV2, "runtime.chanrecv2", P3(TYPE, CHAN, POINTER), - R1(BOOL)) - - -// Start building a select statement. -DEF_GO_RUNTIME(NEWSELECT, "runtime.newselect", P1(INT32), R1(POINTER)) - -// Add a default clause to a select statement. -DEF_GO_RUNTIME(SELECTDEFAULT, "runtime.selectdefault", - P2(POINTER, INT32), R0()) - -// Add a send clause to a select statement. -DEF_GO_RUNTIME(SELECTSEND, "runtime.selectsend", - P4(POINTER, CHAN, POINTER, INT32), R0()) - -// Add a receive clause to a select statement, for a clause which does -// not check whether the channel is closed. -DEF_GO_RUNTIME(SELECTRECV, "runtime.selectrecv", - P4(POINTER, CHAN, POINTER, INT32), R0()) - -// Add a receive clause to a select statement, for a clause which does -// check whether the channel is closed. -DEF_GO_RUNTIME(SELECTRECV2, "runtime.selectrecv2", - P5(POINTER, CHAN, POINTER, BOOLPTR, INT32), R0()) - -// Run a select, returning the index of the selected clause. -DEF_GO_RUNTIME(SELECTGO, "runtime.selectgo", P1(POINTER), R1(INT32)) - - -// Panic. -DEF_GO_RUNTIME(PANIC, "__go_panic", P1(EFACE), R0()) - -// Recover. -DEF_GO_RUNTIME(RECOVER, "__go_recover", P0(), R1(EFACE)) - -// Recover when called directly from defer. -DEF_GO_RUNTIME(DEFERRED_RECOVER, "__go_deferred_recover", P0(), R1(EFACE)) - -// Decide whether this function can call recover. -DEF_GO_RUNTIME(CAN_RECOVER, "__go_can_recover", P1(POINTER), R1(BOOL)) - -// Get the return address of the function. -DEF_GO_RUNTIME(RETURN_ADDRESS, "__go_return_address", P1(INT), R1(POINTER)) - -// Set the return address for defer in a defer thunk. -DEF_GO_RUNTIME(SET_DEFER_RETADDR, "__go_set_defer_retaddr", P1(POINTER), - R1(BOOL)) - -// Check for a deferred function in an exception handler. -DEF_GO_RUNTIME(CHECK_DEFER, "__go_check_defer", P1(BOOLPTR), R0()) - -// Run deferred functions. -DEF_GO_RUNTIME(UNDEFER, "__go_undefer", P1(BOOLPTR), R0()) - -// Panic with a runtime error. -DEF_GO_RUNTIME(RUNTIME_ERROR, "__go_runtime_error", P1(INT32), R0()) - - -// Close. -DEF_GO_RUNTIME(CLOSE, "__go_close", P1(CHAN), R0()) - - -// Copy. -DEF_GO_RUNTIME(COPY, "__go_copy", P3(POINTER, POINTER, UINTPTR), R0()) - -// Append. -DEF_GO_RUNTIME(APPEND, "__go_append", P4(SLICE, POINTER, UINTPTR, UINTPTR), - R1(SLICE)) - - -// Register roots (global variables) for the garbage collector. -DEF_GO_RUNTIME(REGISTER_GC_ROOTS, "__go_register_gc_roots", P1(POINTER), R0()) - - -// Allocate memory. -DEF_GO_RUNTIME(NEW, "__go_new", P1(UINTPTR), R1(POINTER)) - -// Allocate memory which can not contain pointers. -DEF_GO_RUNTIME(NEW_NOPOINTERS, "__go_new_nopointers", P1(UINTPTR), R1(POINTER)) - - -// Allocate a trampoline for a function literal. -DEF_GO_RUNTIME(ALLOCATE_GO_TRAMPOLINE, "__go_allocate_trampoline", - P2(UINTPTR, POINTER), R1(POINTER)) - - -// Start a new goroutine. -DEF_GO_RUNTIME(GO, "__go_go", P2(FUNC_PTR, POINTER), R0()) - - -// Defer a function. -DEF_GO_RUNTIME(DEFER, "__go_defer", P3(BOOLPTR, FUNC_PTR, POINTER), R0()) - - -// Convert an empty interface to an empty interface, returning ok. -DEF_GO_RUNTIME(IFACEE2E2, "runtime.ifaceE2E2", P1(EFACE), R2(EFACE, BOOL)) - -// Convert a non-empty interface to an empty interface, returning ok. -DEF_GO_RUNTIME(IFACEI2E2, "runtime.ifaceI2E2", P1(IFACE), R2(EFACE, BOOL)) - -// Convert an empty interface to a non-empty interface, returning ok. -DEF_GO_RUNTIME(IFACEE2I2, "runtime.ifaceE2I2", P2(TYPE, EFACE), - R2(IFACE, BOOL)) - -// Convert a non-empty interface to a non-empty interface, returning ok. -DEF_GO_RUNTIME(IFACEI2I2, "runtime.ifaceI2I2", P2(TYPE, IFACE), - R2(IFACE, BOOL)) - -// Convert an empty interface to a pointer type, returning ok. -DEF_GO_RUNTIME(IFACEE2T2P, "runtime.ifaceE2T2P", P2(TYPE, EFACE), - R2(POINTER, BOOL)) - -// Convert a non-empty interface to a pointer type, return ok. -DEF_GO_RUNTIME(IFACEI2T2P, "runtime.ifaceI2T2P", P2(TYPE, IFACE), - R2(POINTER, BOOL)) - -// Convert an empty interface to a non-pointer type, returning ok. -DEF_GO_RUNTIME(IFACEE2T2, "runtime.ifaceE2T2", P3(TYPE, EFACE, POINTER), - R1(BOOL)) - -// Convert a non-empty interface to a non-pointer type, returning ok. -DEF_GO_RUNTIME(IFACEI2T2, "runtime.ifaceI2T2", P3(TYPE, IFACE, POINTER), - R1(BOOL)) - -// A type assertion from one interface type to another. This is -// used for a type assertion. -DEF_GO_RUNTIME(ASSERT_INTERFACE, "__go_assert_interface", P2(TYPE, TYPE), R0()) - -// Convert one interface type to another. This is used for an -// assignment. -DEF_GO_RUNTIME(CONVERT_INTERFACE, "__go_convert_interface", P2(TYPE, TYPE), - R1(POINTER)) - -// Check whether an interface type may be converted to a -// non-interface type. -DEF_GO_RUNTIME(CHECK_INTERFACE_TYPE, "__go_check_interface_type", - P3(TYPE, TYPE, TYPE), R0()) - -// Return whether we can convert an interface type to a type. -DEF_GO_RUNTIME(IFACEI2TP, "runtime.ifaceI2Tp", P2(TYPE, TYPE), R1(BOOL)) - -// Get the type descriptor of an empty interface. -DEF_GO_RUNTIME(EFACETYPE, "runtime.efacetype", P1(EFACE), R1(TYPE)) - -// Get the type descriptor of a non-empty interface. -DEF_GO_RUNTIME(IFACETYPE, "runtime.ifacetype", P1(IFACE), R1(TYPE)) - - -// Compare two type descriptors for equality. -DEF_GO_RUNTIME(IFACETYPEEQ, "runtime.ifacetypeeq", P2(TYPE, TYPE), R1(BOOL)) - -// Compare two empty interface values. -DEF_GO_RUNTIME(EMPTY_INTERFACE_COMPARE, "__go_empty_interface_compare", - P2(EFACE, EFACE), R1(INT)) - -// Compare an empty interface value to a non-interface value. -DEF_GO_RUNTIME(EMPTY_INTERFACE_VALUE_COMPARE, - "__go_empty_interface_value_compare", - P3(EFACE, TYPE, POINTER), R1(INT)) - -// Compare two non-empty interface values. -DEF_GO_RUNTIME(INTERFACE_COMPARE, "__go_interface_compare", - P2(IFACE, IFACE), R1(INT)) - -// Compare a non-empty interface value to a non-interface value. -DEF_GO_RUNTIME(INTERFACE_VALUE_COMPARE, "__go_interface_value_compare", - P3(IFACE, TYPE, POINTER), R1(INT)) - -// Compare a non-empty interface value to an interface value. -DEF_GO_RUNTIME(INTERFACE_EMPTY_COMPARE, "__go_interface_empty_compare", - P2(IFACE, EFACE), R1(INT)) - - -// Print a string (for print/println). -DEF_GO_RUNTIME(PRINT_STRING, "__go_print_string", P1(STRING), R0()) - -// Print a uint64 (for print/println). -DEF_GO_RUNTIME(PRINT_UINT64, "__go_print_uint64", P1(UINT64), R0()) - -// Print a int64 (for print/println). -DEF_GO_RUNTIME(PRINT_INT64, "__go_print_int64", P1(INT64), R0()) - -// Print a float64 (for print/println). -DEF_GO_RUNTIME(PRINT_DOUBLE, "__go_print_double", P1(FLOAT64), R0()) - -// Print a complex128 (for print/println). -DEF_GO_RUNTIME(PRINT_COMPLEX, "__go_print_complex", P1(COMPLEX128), R0()) - -// Print a bool (for print/println). -DEF_GO_RUNTIME(PRINT_BOOL, "__go_print_bool", P1(BOOL), R0()) - -// Print a pointer/map/channel/function (for print/println). -DEF_GO_RUNTIME(PRINT_POINTER, "__go_print_pointer", P1(POINTER), R0()) - -// Print an empty interface (for print/println). -DEF_GO_RUNTIME(PRINT_EMPTY_INTERFACE, "__go_print_empty_interface", - P1(EFACE), R0()) - -// Print a non-empty interface (for print/println). -DEF_GO_RUNTIME(PRINT_INTERFACE, "__go_print_interface", P1(IFACE), R0()) - -// Print a slice (for print/println). -DEF_GO_RUNTIME(PRINT_SLICE, "__go_print_slice", P1(SLICE), R0()) - -// Print a space (for println). -DEF_GO_RUNTIME(PRINT_SPACE, "__go_print_space", P0(), R0()) - -// Print a newline (for println). -DEF_GO_RUNTIME(PRINT_NL, "__go_print_nl", P0(), R0()) - - -// Used for field tracking for data analysis. -DEF_GO_RUNTIME(FIELDTRACK, "__go_fieldtrack", P1(POINTER), R0()) - - -// Remove helper macros. -#undef ABFT6 -#undef ABFT2 -#undef P0 -#undef P1 -#undef P2 -#undef P3 -#undef P4 -#undef P5 -#undef P6 -#undef R0 -#undef R1 -#undef R2 diff --git a/gcc-4.8.1/gcc/go/gofrontend/runtime.h b/gcc-4.8.1/gcc/go/gofrontend/runtime.h deleted file mode 100644 index be5dcbe25..000000000 --- a/gcc-4.8.1/gcc/go/gofrontend/runtime.h +++ /dev/null @@ -1,51 +0,0 @@ -// runtime.h -- runtime functions called by generated code -*- C++ -*- - -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#ifndef GO_RUNTIME_H -#define GO_RUNTIME_H - -class Gogo; -class Type; -class Named_object; -class Call_expression; - -class Runtime -{ - public: - - // The runtime functions which may be called by generated code. - enum Function - { - -#define DEF_GO_RUNTIME(CODE, NAME, PARAMS, RESULTS) CODE , - -#include "runtime.def" - -#undef DEF_GO_RUNTIME - - // Number of runtime functions. - NUMBER_OF_FUNCTIONS - }; - - // Make a call to a runtime function. - static Call_expression* - make_call(Function, Location, int, ...); - - // Convert all the types used by runtime functions to the backend - // representation. - static void - convert_types(Gogo*); - - // Return the type used for iterations over maps. - static Type* - map_iteration_type(); - - private: - static Named_object* - runtime_declaration(Function); -}; - -#endif // !defined(GO_BUILTINS_H) diff --git a/gcc-4.8.1/gcc/go/gofrontend/statements.cc b/gcc-4.8.1/gcc/go/gofrontend/statements.cc deleted file mode 100644 index 7870dad72..000000000 --- a/gcc-4.8.1/gcc/go/gofrontend/statements.cc +++ /dev/null @@ -1,5918 +0,0 @@ -// statements.cc -- Go frontend statements. - -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "go-system.h" - -#include "go-c.h" -#include "types.h" -#include "expressions.h" -#include "gogo.h" -#include "runtime.h" -#include "backend.h" -#include "statements.h" -#include "ast-dump.h" - -// Class Statement. - -Statement::Statement(Statement_classification classification, - Location location) - : classification_(classification), location_(location) -{ -} - -Statement::~Statement() -{ -} - -// Traverse the tree. The work of walking the components is handled -// by the subclasses. - -int -Statement::traverse(Block* block, size_t* pindex, Traverse* traverse) -{ - if (this->classification_ == STATEMENT_ERROR) - return TRAVERSE_CONTINUE; - - unsigned int traverse_mask = traverse->traverse_mask(); - - if ((traverse_mask & Traverse::traverse_statements) != 0) - { - int t = traverse->statement(block, pindex, this); - if (t == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - else if (t == TRAVERSE_SKIP_COMPONENTS) - return TRAVERSE_CONTINUE; - } - - // No point in checking traverse_mask here--a statement may contain - // other blocks or statements, and if we got here we always want to - // walk them. - return this->do_traverse(traverse); -} - -// Traverse the contents of a statement. - -int -Statement::traverse_contents(Traverse* traverse) -{ - return this->do_traverse(traverse); -} - -// Traverse assignments. - -bool -Statement::traverse_assignments(Traverse_assignments* tassign) -{ - if (this->classification_ == STATEMENT_ERROR) - return false; - return this->do_traverse_assignments(tassign); -} - -// Traverse an expression in a statement. This is a helper function -// for child classes. - -int -Statement::traverse_expression(Traverse* traverse, Expression** expr) -{ - if ((traverse->traverse_mask() - & (Traverse::traverse_types | Traverse::traverse_expressions)) == 0) - return TRAVERSE_CONTINUE; - return Expression::traverse(expr, traverse); -} - -// Traverse an expression list in a statement. This is a helper -// function for child classes. - -int -Statement::traverse_expression_list(Traverse* traverse, - Expression_list* expr_list) -{ - if (expr_list == NULL) - return TRAVERSE_CONTINUE; - if ((traverse->traverse_mask() - & (Traverse::traverse_types | Traverse::traverse_expressions)) == 0) - return TRAVERSE_CONTINUE; - return expr_list->traverse(traverse); -} - -// Traverse a type in a statement. This is a helper function for -// child classes. - -int -Statement::traverse_type(Traverse* traverse, Type* type) -{ - if ((traverse->traverse_mask() - & (Traverse::traverse_types | Traverse::traverse_expressions)) == 0) - return TRAVERSE_CONTINUE; - return Type::traverse(type, traverse); -} - -// Set type information for unnamed constants. This is really done by -// the child class. - -void -Statement::determine_types() -{ - this->do_determine_types(); -} - -// If this is a thunk statement, return it. - -Thunk_statement* -Statement::thunk_statement() -{ - Thunk_statement* ret = this->convert<Thunk_statement, STATEMENT_GO>(); - if (ret == NULL) - ret = this->convert<Thunk_statement, STATEMENT_DEFER>(); - return ret; -} - -// Convert a Statement to the backend representation. This is really -// done by the child class. - -Bstatement* -Statement::get_backend(Translate_context* context) -{ - if (this->classification_ == STATEMENT_ERROR) - return context->backend()->error_statement(); - return this->do_get_backend(context); -} - -// Dump AST representation for a statement to a dump context. - -void -Statement::dump_statement(Ast_dump_context* ast_dump_context) const -{ - this->do_dump_statement(ast_dump_context); -} - -// Note that this statement is erroneous. This is called by children -// when they discover an error. - -void -Statement::set_is_error() -{ - this->classification_ = STATEMENT_ERROR; -} - -// For children to call to report an error conveniently. - -void -Statement::report_error(const char* msg) -{ - error_at(this->location_, "%s", msg); - this->set_is_error(); -} - -// An error statement, used to avoid crashing after we report an -// error. - -class Error_statement : public Statement -{ - public: - Error_statement(Location location) - : Statement(STATEMENT_ERROR, location) - { } - - protected: - int - do_traverse(Traverse*) - { return TRAVERSE_CONTINUE; } - - Bstatement* - do_get_backend(Translate_context*) - { go_unreachable(); } - - void - do_dump_statement(Ast_dump_context*) const; -}; - -// Dump the AST representation for an error statement. - -void -Error_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const -{ - ast_dump_context->print_indent(); - ast_dump_context->ostream() << "Error statement" << std::endl; -} - -// Make an error statement. - -Statement* -Statement::make_error_statement(Location location) -{ - return new Error_statement(location); -} - -// Class Variable_declaration_statement. - -Variable_declaration_statement::Variable_declaration_statement( - Named_object* var) - : Statement(STATEMENT_VARIABLE_DECLARATION, var->var_value()->location()), - var_(var) -{ -} - -// We don't actually traverse the variable here; it was traversed -// while traversing the Block. - -int -Variable_declaration_statement::do_traverse(Traverse*) -{ - return TRAVERSE_CONTINUE; -} - -// Traverse the assignments in a variable declaration. Note that this -// traversal is different from the usual traversal. - -bool -Variable_declaration_statement::do_traverse_assignments( - Traverse_assignments* tassign) -{ - tassign->initialize_variable(this->var_); - return true; -} - -// Lower the variable's initialization expression. - -Statement* -Variable_declaration_statement::do_lower(Gogo* gogo, Named_object* function, - Block*, Statement_inserter* inserter) -{ - this->var_->var_value()->lower_init_expression(gogo, function, inserter); - return this; -} - -// Convert a variable declaration to the backend representation. - -Bstatement* -Variable_declaration_statement::do_get_backend(Translate_context* context) -{ - Variable* var = this->var_->var_value(); - Bvariable* bvar = this->var_->get_backend_variable(context->gogo(), - context->function()); - tree init = var->get_init_tree(context->gogo(), context->function()); - Bexpression* binit = init == NULL ? NULL : tree_to_expr(init); - - if (!var->is_in_heap()) - { - go_assert(binit != NULL); - return context->backend()->init_statement(bvar, binit); - } - - // Something takes the address of this variable, so the value is - // stored in the heap. Initialize it to newly allocated memory - // space, and assign the initial value to the new space. - Location loc = this->location(); - Named_object* newfn = context->gogo()->lookup_global("new"); - go_assert(newfn != NULL && newfn->is_function_declaration()); - Expression* func = Expression::make_func_reference(newfn, NULL, loc); - Expression_list* params = new Expression_list(); - params->push_back(Expression::make_type(var->type(), loc)); - Expression* call = Expression::make_call(func, params, false, loc); - context->gogo()->lower_expression(context->function(), NULL, &call); - Temporary_statement* temp = Statement::make_temporary(NULL, call, loc); - Bstatement* btemp = temp->get_backend(context); - - Bstatement* set = NULL; - if (binit != NULL) - { - Expression* e = Expression::make_temporary_reference(temp, loc); - e = Expression::make_unary(OPERATOR_MULT, e, loc); - Bexpression* be = tree_to_expr(e->get_tree(context)); - set = context->backend()->assignment_statement(be, binit, loc); - } - - Expression* ref = Expression::make_temporary_reference(temp, loc); - Bexpression* bref = tree_to_expr(ref->get_tree(context)); - Bstatement* sinit = context->backend()->init_statement(bvar, bref); - - std::vector<Bstatement*> stats; - stats.reserve(3); - stats.push_back(btemp); - if (set != NULL) - stats.push_back(set); - stats.push_back(sinit); - return context->backend()->statement_list(stats); -} - -// Dump the AST representation for a variable declaration. - -void -Variable_declaration_statement::do_dump_statement( - Ast_dump_context* ast_dump_context) const -{ - ast_dump_context->print_indent(); - - go_assert(var_->is_variable()); - ast_dump_context->ostream() << "var " << this->var_->name() << " "; - Variable* var = this->var_->var_value(); - if (var->has_type()) - { - ast_dump_context->dump_type(var->type()); - ast_dump_context->ostream() << " "; - } - if (var->init() != NULL) - { - ast_dump_context->ostream() << "= "; - ast_dump_context->dump_expression(var->init()); - } - ast_dump_context->ostream() << std::endl; -} - -// Make a variable declaration. - -Statement* -Statement::make_variable_declaration(Named_object* var) -{ - return new Variable_declaration_statement(var); -} - -// Class Temporary_statement. - -// Return the type of the temporary variable. - -Type* -Temporary_statement::type() const -{ - return this->type_ != NULL ? this->type_ : this->init_->type(); -} - -// Traversal. - -int -Temporary_statement::do_traverse(Traverse* traverse) -{ - if (this->type_ != NULL - && this->traverse_type(traverse, this->type_) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - if (this->init_ == NULL) - return TRAVERSE_CONTINUE; - else - return this->traverse_expression(traverse, &this->init_); -} - -// Traverse assignments. - -bool -Temporary_statement::do_traverse_assignments(Traverse_assignments* tassign) -{ - if (this->init_ == NULL) - return false; - tassign->value(&this->init_, true, true); - return true; -} - -// Determine types. - -void -Temporary_statement::do_determine_types() -{ - if (this->type_ != NULL && this->type_->is_abstract()) - this->type_ = this->type_->make_non_abstract_type(); - - if (this->init_ != NULL) - { - if (this->type_ == NULL) - this->init_->determine_type_no_context(); - else - { - Type_context context(this->type_, false); - this->init_->determine_type(&context); - } - } - - if (this->type_ == NULL) - { - this->type_ = this->init_->type(); - go_assert(!this->type_->is_abstract()); - } -} - -// Check types. - -void -Temporary_statement::do_check_types(Gogo*) -{ - if (this->type_ != NULL && this->init_ != NULL) - { - std::string reason; - bool ok; - if (this->are_hidden_fields_ok_) - ok = Type::are_assignable_hidden_ok(this->type_, this->init_->type(), - &reason); - else - ok = Type::are_assignable(this->type_, this->init_->type(), &reason); - if (!ok) - { - if (reason.empty()) - error_at(this->location(), "incompatible types in assignment"); - else - error_at(this->location(), "incompatible types in assignment (%s)", - reason.c_str()); - this->set_is_error(); - } - } -} - -// Convert to backend representation. - -Bstatement* -Temporary_statement::do_get_backend(Translate_context* context) -{ - go_assert(this->bvariable_ == NULL); - - // FIXME: Permitting FUNCTION to be NULL here is a temporary measure - // until we have a better representation of the init function. - Named_object* function = context->function(); - Bfunction* bfunction; - if (function == NULL) - bfunction = NULL; - else - bfunction = tree_to_function(function->func_value()->get_decl()); - - Btype* btype = this->type()->get_backend(context->gogo()); - - Bexpression* binit; - if (this->init_ == NULL) - binit = NULL; - else if (this->type_ == NULL) - binit = tree_to_expr(this->init_->get_tree(context)); - else - { - Expression* init = Expression::make_cast(this->type_, this->init_, - this->location()); - context->gogo()->lower_expression(context->function(), NULL, &init); - binit = tree_to_expr(init->get_tree(context)); - } - - Bstatement* statement; - this->bvariable_ = - context->backend()->temporary_variable(bfunction, context->bblock(), - btype, binit, - this->is_address_taken_, - this->location(), &statement); - return statement; -} - -// Return the backend variable. - -Bvariable* -Temporary_statement::get_backend_variable(Translate_context* context) const -{ - if (this->bvariable_ == NULL) - { - go_assert(saw_errors()); - return context->backend()->error_variable(); - } - return this->bvariable_; -} - -// Dump the AST represemtation for a temporary statement - -void -Temporary_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const -{ - ast_dump_context->print_indent(); - ast_dump_context->dump_temp_variable_name(this); - if (this->type_ != NULL) - { - ast_dump_context->ostream() << " "; - ast_dump_context->dump_type(this->type_); - } - if (this->init_ != NULL) - { - ast_dump_context->ostream() << " = "; - ast_dump_context->dump_expression(this->init_); - } - ast_dump_context->ostream() << std::endl; -} - -// Make and initialize a temporary variable in BLOCK. - -Temporary_statement* -Statement::make_temporary(Type* type, Expression* init, - Location location) -{ - return new Temporary_statement(type, init, location); -} - -// An assignment statement. - -class Assignment_statement : public Statement -{ - public: - Assignment_statement(Expression* lhs, Expression* rhs, - Location location) - : Statement(STATEMENT_ASSIGNMENT, location), - lhs_(lhs), rhs_(rhs), are_hidden_fields_ok_(false) - { } - - // Note that it is OK for this assignment statement to set hidden - // fields. - void - set_hidden_fields_are_ok() - { this->are_hidden_fields_ok_ = true; } - - protected: - int - do_traverse(Traverse* traverse); - - bool - do_traverse_assignments(Traverse_assignments*); - - void - do_determine_types(); - - void - do_check_types(Gogo*); - - Bstatement* - do_get_backend(Translate_context*); - - void - do_dump_statement(Ast_dump_context*) const; - - private: - // Left hand side--the lvalue. - Expression* lhs_; - // Right hand side--the rvalue. - Expression* rhs_; - // True if this statement may set hidden fields in the assignment - // statement. This is used for generated method stubs. - bool are_hidden_fields_ok_; -}; - -// Traversal. - -int -Assignment_statement::do_traverse(Traverse* traverse) -{ - if (this->traverse_expression(traverse, &this->lhs_) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - return this->traverse_expression(traverse, &this->rhs_); -} - -bool -Assignment_statement::do_traverse_assignments(Traverse_assignments* tassign) -{ - tassign->assignment(&this->lhs_, &this->rhs_); - return true; -} - -// Set types for the assignment. - -void -Assignment_statement::do_determine_types() -{ - this->lhs_->determine_type_no_context(); - Type_context context(this->lhs_->type(), false); - this->rhs_->determine_type(&context); -} - -// Check types for an assignment. - -void -Assignment_statement::do_check_types(Gogo*) -{ - // The left hand side must be either addressable, a map index - // expression, or the blank identifier. - if (!this->lhs_->is_addressable() - && this->lhs_->map_index_expression() == NULL - && !this->lhs_->is_sink_expression()) - { - if (!this->lhs_->type()->is_error()) - this->report_error(_("invalid left hand side of assignment")); - return; - } - - Type* lhs_type = this->lhs_->type(); - Type* rhs_type = this->rhs_->type(); - std::string reason; - bool ok; - if (this->are_hidden_fields_ok_) - ok = Type::are_assignable_hidden_ok(lhs_type, rhs_type, &reason); - else - ok = Type::are_assignable(lhs_type, rhs_type, &reason); - if (!ok) - { - if (reason.empty()) - error_at(this->location(), "incompatible types in assignment"); - else - error_at(this->location(), "incompatible types in assignment (%s)", - reason.c_str()); - this->set_is_error(); - } - - if (lhs_type->is_error() || rhs_type->is_error()) - this->set_is_error(); -} - -// Convert an assignment statement to the backend representation. - -Bstatement* -Assignment_statement::do_get_backend(Translate_context* context) -{ - tree rhs_tree = this->rhs_->get_tree(context); - if (this->lhs_->is_sink_expression()) - return context->backend()->expression_statement(tree_to_expr(rhs_tree)); - tree lhs_tree = this->lhs_->get_tree(context); - rhs_tree = Expression::convert_for_assignment(context, this->lhs_->type(), - this->rhs_->type(), rhs_tree, - this->location()); - return context->backend()->assignment_statement(tree_to_expr(lhs_tree), - tree_to_expr(rhs_tree), - this->location()); -} - -// Dump the AST representation for an assignment statement. - -void -Assignment_statement::do_dump_statement(Ast_dump_context* ast_dump_context) - const -{ - ast_dump_context->print_indent(); - ast_dump_context->dump_expression(this->lhs_); - ast_dump_context->ostream() << " = " ; - ast_dump_context->dump_expression(this->rhs_); - ast_dump_context->ostream() << std::endl; -} - -// Make an assignment statement. - -Statement* -Statement::make_assignment(Expression* lhs, Expression* rhs, - Location location) -{ - return new Assignment_statement(lhs, rhs, location); -} - -// The Move_subexpressions class is used to move all top-level -// subexpressions of an expression. This is used for things like -// index expressions in which we must evaluate the index value before -// it can be changed by a multiple assignment. - -class Move_subexpressions : public Traverse -{ - public: - Move_subexpressions(int skip, Block* block) - : Traverse(traverse_expressions), - skip_(skip), block_(block) - { } - - protected: - int - expression(Expression**); - - private: - // The number of subexpressions to skip moving. This is used to - // avoid moving the array itself, as we only need to move the index. - int skip_; - // The block where new temporary variables should be added. - Block* block_; -}; - -int -Move_subexpressions::expression(Expression** pexpr) -{ - if (this->skip_ > 0) - --this->skip_; - else if ((*pexpr)->temporary_reference_expression() == NULL) - { - Location loc = (*pexpr)->location(); - Temporary_statement* temp = Statement::make_temporary(NULL, *pexpr, loc); - this->block_->add_statement(temp); - *pexpr = Expression::make_temporary_reference(temp, loc); - } - // We only need to move top-level subexpressions. - return TRAVERSE_SKIP_COMPONENTS; -} - -// The Move_ordered_evals class is used to find any subexpressions of -// an expression that have an evaluation order dependency. It creates -// temporary variables to hold them. - -class Move_ordered_evals : public Traverse -{ - public: - Move_ordered_evals(Block* block) - : Traverse(traverse_expressions), - block_(block) - { } - - protected: - int - expression(Expression**); - - private: - // The block where new temporary variables should be added. - Block* block_; -}; - -int -Move_ordered_evals::expression(Expression** pexpr) -{ - // We have to look at subexpressions first. - if ((*pexpr)->traverse_subexpressions(this) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - - int i; - if ((*pexpr)->must_eval_subexpressions_in_order(&i)) - { - Move_subexpressions ms(i, this->block_); - if ((*pexpr)->traverse_subexpressions(&ms) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - - if ((*pexpr)->must_eval_in_order()) - { - Location loc = (*pexpr)->location(); - Temporary_statement* temp = Statement::make_temporary(NULL, *pexpr, loc); - this->block_->add_statement(temp); - *pexpr = Expression::make_temporary_reference(temp, loc); - } - return TRAVERSE_SKIP_COMPONENTS; -} - -// An assignment operation statement. - -class Assignment_operation_statement : public Statement -{ - public: - Assignment_operation_statement(Operator op, Expression* lhs, Expression* rhs, - Location location) - : Statement(STATEMENT_ASSIGNMENT_OPERATION, location), - op_(op), lhs_(lhs), rhs_(rhs) - { } - - protected: - int - do_traverse(Traverse*); - - bool - do_traverse_assignments(Traverse_assignments*) - { go_unreachable(); } - - Statement* - do_lower(Gogo*, Named_object*, Block*, Statement_inserter*); - - Bstatement* - do_get_backend(Translate_context*) - { go_unreachable(); } - - void - do_dump_statement(Ast_dump_context*) const; - - private: - // The operator (OPERATOR_PLUSEQ, etc.). - Operator op_; - // Left hand side. - Expression* lhs_; - // Right hand side. - Expression* rhs_; -}; - -// Traversal. - -int -Assignment_operation_statement::do_traverse(Traverse* traverse) -{ - if (this->traverse_expression(traverse, &this->lhs_) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - return this->traverse_expression(traverse, &this->rhs_); -} - -// Lower an assignment operation statement to a regular assignment -// statement. - -Statement* -Assignment_operation_statement::do_lower(Gogo*, Named_object*, - Block* enclosing, Statement_inserter*) -{ - Location loc = this->location(); - - // We have to evaluate the left hand side expression only once. We - // do this by moving out any expression with side effects. - Block* b = new Block(enclosing, loc); - Move_ordered_evals moe(b); - this->lhs_->traverse_subexpressions(&moe); - - Expression* lval = this->lhs_->copy(); - - Operator op; - switch (this->op_) - { - case OPERATOR_PLUSEQ: - op = OPERATOR_PLUS; - break; - case OPERATOR_MINUSEQ: - op = OPERATOR_MINUS; - break; - case OPERATOR_OREQ: - op = OPERATOR_OR; - break; - case OPERATOR_XOREQ: - op = OPERATOR_XOR; - break; - case OPERATOR_MULTEQ: - op = OPERATOR_MULT; - break; - case OPERATOR_DIVEQ: - op = OPERATOR_DIV; - break; - case OPERATOR_MODEQ: - op = OPERATOR_MOD; - break; - case OPERATOR_LSHIFTEQ: - op = OPERATOR_LSHIFT; - break; - case OPERATOR_RSHIFTEQ: - op = OPERATOR_RSHIFT; - break; - case OPERATOR_ANDEQ: - op = OPERATOR_AND; - break; - case OPERATOR_BITCLEAREQ: - op = OPERATOR_BITCLEAR; - break; - default: - go_unreachable(); - } - - Expression* binop = Expression::make_binary(op, lval, this->rhs_, loc); - Statement* s = Statement::make_assignment(this->lhs_, binop, loc); - if (b->statements()->empty()) - { - delete b; - return s; - } - else - { - b->add_statement(s); - return Statement::make_block_statement(b, loc); - } -} - -// Dump the AST representation for an assignment operation statement - -void -Assignment_operation_statement::do_dump_statement( - Ast_dump_context* ast_dump_context) const -{ - ast_dump_context->print_indent(); - ast_dump_context->dump_expression(this->lhs_); - ast_dump_context->dump_operator(this->op_); - ast_dump_context->dump_expression(this->rhs_); - ast_dump_context->ostream() << std::endl; -} - -// Make an assignment operation statement. - -Statement* -Statement::make_assignment_operation(Operator op, Expression* lhs, - Expression* rhs, Location location) -{ - return new Assignment_operation_statement(op, lhs, rhs, location); -} - -// A tuple assignment statement. This differs from an assignment -// statement in that the right-hand-side expressions are evaluated in -// parallel. - -class Tuple_assignment_statement : public Statement -{ - public: - Tuple_assignment_statement(Expression_list* lhs, Expression_list* rhs, - Location location) - : Statement(STATEMENT_TUPLE_ASSIGNMENT, location), - lhs_(lhs), rhs_(rhs), are_hidden_fields_ok_(false) - { } - - // Note that it is OK for this assignment statement to set hidden - // fields. - void - set_hidden_fields_are_ok() - { this->are_hidden_fields_ok_ = true; } - - protected: - int - do_traverse(Traverse* traverse); - - bool - do_traverse_assignments(Traverse_assignments*) - { go_unreachable(); } - - Statement* - do_lower(Gogo*, Named_object*, Block*, Statement_inserter*); - - Bstatement* - do_get_backend(Translate_context*) - { go_unreachable(); } - - void - do_dump_statement(Ast_dump_context*) const; - - private: - // Left hand side--a list of lvalues. - Expression_list* lhs_; - // Right hand side--a list of rvalues. - Expression_list* rhs_; - // True if this statement may set hidden fields in the assignment - // statement. This is used for generated method stubs. - bool are_hidden_fields_ok_; -}; - -// Traversal. - -int -Tuple_assignment_statement::do_traverse(Traverse* traverse) -{ - if (this->traverse_expression_list(traverse, this->lhs_) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - return this->traverse_expression_list(traverse, this->rhs_); -} - -// Lower a tuple assignment. We use temporary variables to split it -// up into a set of single assignments. - -Statement* -Tuple_assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing, - Statement_inserter*) -{ - Location loc = this->location(); - - Block* b = new Block(enclosing, loc); - - // First move out any subexpressions on the left hand side. The - // right hand side will be evaluated in the required order anyhow. - Move_ordered_evals moe(b); - for (Expression_list::iterator plhs = this->lhs_->begin(); - plhs != this->lhs_->end(); - ++plhs) - Expression::traverse(&*plhs, &moe); - - std::vector<Temporary_statement*> temps; - temps.reserve(this->lhs_->size()); - - Expression_list::const_iterator prhs = this->rhs_->begin(); - for (Expression_list::const_iterator plhs = this->lhs_->begin(); - plhs != this->lhs_->end(); - ++plhs, ++prhs) - { - go_assert(prhs != this->rhs_->end()); - - if ((*plhs)->is_error_expression() - || (*plhs)->type()->is_error() - || (*prhs)->is_error_expression() - || (*prhs)->type()->is_error()) - continue; - - if ((*plhs)->is_sink_expression()) - { - b->add_statement(Statement::make_statement(*prhs, true)); - continue; - } - - Temporary_statement* temp = Statement::make_temporary((*plhs)->type(), - *prhs, loc); - if (this->are_hidden_fields_ok_) - temp->set_hidden_fields_are_ok(); - b->add_statement(temp); - temps.push_back(temp); - - } - go_assert(prhs == this->rhs_->end()); - - prhs = this->rhs_->begin(); - std::vector<Temporary_statement*>::const_iterator ptemp = temps.begin(); - for (Expression_list::const_iterator plhs = this->lhs_->begin(); - plhs != this->lhs_->end(); - ++plhs, ++prhs) - { - if ((*plhs)->is_error_expression() - || (*plhs)->type()->is_error() - || (*prhs)->is_error_expression() - || (*prhs)->type()->is_error()) - continue; - - if ((*plhs)->is_sink_expression()) - continue; - - Expression* ref = Expression::make_temporary_reference(*ptemp, loc); - Statement* s = Statement::make_assignment(*plhs, ref, loc); - if (this->are_hidden_fields_ok_) - { - Assignment_statement* as = static_cast<Assignment_statement*>(s); - as->set_hidden_fields_are_ok(); - } - b->add_statement(s); - ++ptemp; - } - go_assert(ptemp == temps.end() || saw_errors()); - - return Statement::make_block_statement(b, loc); -} - -// Dump the AST representation for a tuple assignment statement. - -void -Tuple_assignment_statement::do_dump_statement( - Ast_dump_context* ast_dump_context) const -{ - ast_dump_context->print_indent(); - ast_dump_context->dump_expression_list(this->lhs_); - ast_dump_context->ostream() << " = "; - ast_dump_context->dump_expression_list(this->rhs_); - ast_dump_context->ostream() << std::endl; -} - -// Make a tuple assignment statement. - -Statement* -Statement::make_tuple_assignment(Expression_list* lhs, Expression_list* rhs, - Location location) -{ - return new Tuple_assignment_statement(lhs, rhs, location); -} - -// A tuple assignment from a map index expression. -// v, ok = m[k] - -class Tuple_map_assignment_statement : public Statement -{ -public: - Tuple_map_assignment_statement(Expression* val, Expression* present, - Expression* map_index, - Location location) - : Statement(STATEMENT_TUPLE_MAP_ASSIGNMENT, location), - val_(val), present_(present), map_index_(map_index) - { } - - protected: - int - do_traverse(Traverse* traverse); - - bool - do_traverse_assignments(Traverse_assignments*) - { go_unreachable(); } - - Statement* - do_lower(Gogo*, Named_object*, Block*, Statement_inserter*); - - Bstatement* - do_get_backend(Translate_context*) - { go_unreachable(); } - - void - do_dump_statement(Ast_dump_context*) const; - - private: - // Lvalue which receives the value from the map. - Expression* val_; - // Lvalue which receives whether the key value was present. - Expression* present_; - // The map index expression. - Expression* map_index_; -}; - -// Traversal. - -int -Tuple_map_assignment_statement::do_traverse(Traverse* traverse) -{ - if (this->traverse_expression(traverse, &this->val_) == TRAVERSE_EXIT - || this->traverse_expression(traverse, &this->present_) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - return this->traverse_expression(traverse, &this->map_index_); -} - -// Lower a tuple map assignment. - -Statement* -Tuple_map_assignment_statement::do_lower(Gogo*, Named_object*, - Block* enclosing, Statement_inserter*) -{ - Location loc = this->location(); - - Map_index_expression* map_index = this->map_index_->map_index_expression(); - if (map_index == NULL) - { - this->report_error(_("expected map index on right hand side")); - return Statement::make_error_statement(loc); - } - Map_type* map_type = map_index->get_map_type(); - if (map_type == NULL) - return Statement::make_error_statement(loc); - - Block* b = new Block(enclosing, loc); - - // Move out any subexpressions to make sure that functions are - // called in the required order. - Move_ordered_evals moe(b); - this->val_->traverse_subexpressions(&moe); - this->present_->traverse_subexpressions(&moe); - - // Copy the key value into a temporary so that we can take its - // address without pushing the value onto the heap. - - // var key_temp KEY_TYPE = MAP_INDEX - Temporary_statement* key_temp = - Statement::make_temporary(map_type->key_type(), map_index->index(), loc); - b->add_statement(key_temp); - - // var val_temp VAL_TYPE - Temporary_statement* val_temp = - Statement::make_temporary(map_type->val_type(), NULL, loc); - b->add_statement(val_temp); - - // var present_temp bool - Temporary_statement* present_temp = - Statement::make_temporary(Type::lookup_bool_type(), NULL, loc); - b->add_statement(present_temp); - - // present_temp = mapaccess2(DESCRIPTOR, MAP, &key_temp, &val_temp) - Expression* a1 = Expression::make_type_descriptor(map_type, loc); - Expression* a2 = map_index->map(); - Temporary_reference_expression* ref = - Expression::make_temporary_reference(key_temp, loc); - Expression* a3 = Expression::make_unary(OPERATOR_AND, ref, loc); - ref = Expression::make_temporary_reference(val_temp, loc); - Expression* a4 = Expression::make_unary(OPERATOR_AND, ref, loc); - Expression* call = Runtime::make_call(Runtime::MAPACCESS2, loc, 4, - a1, a2, a3, a4); - - ref = Expression::make_temporary_reference(present_temp, loc); - ref->set_is_lvalue(); - Statement* s = Statement::make_assignment(ref, call, loc); - b->add_statement(s); - - // val = val_temp - ref = Expression::make_temporary_reference(val_temp, loc); - s = Statement::make_assignment(this->val_, ref, loc); - b->add_statement(s); - - // present = present_temp - ref = Expression::make_temporary_reference(present_temp, loc); - s = Statement::make_assignment(this->present_, ref, loc); - b->add_statement(s); - - return Statement::make_block_statement(b, loc); -} - -// Dump the AST representation for a tuple map assignment statement. - -void -Tuple_map_assignment_statement::do_dump_statement( - Ast_dump_context* ast_dump_context) const -{ - ast_dump_context->print_indent(); - ast_dump_context->dump_expression(this->val_); - ast_dump_context->ostream() << ", "; - ast_dump_context->dump_expression(this->present_); - ast_dump_context->ostream() << " = "; - ast_dump_context->dump_expression(this->map_index_); - ast_dump_context->ostream() << std::endl; -} - -// Make a map assignment statement which returns a pair of values. - -Statement* -Statement::make_tuple_map_assignment(Expression* val, Expression* present, - Expression* map_index, - Location location) -{ - return new Tuple_map_assignment_statement(val, present, map_index, location); -} - -// Assign a pair of entries to a map. -// m[k] = v, p - -class Map_assignment_statement : public Statement -{ - public: - Map_assignment_statement(Expression* map_index, - Expression* val, Expression* should_set, - Location location) - : Statement(STATEMENT_MAP_ASSIGNMENT, location), - map_index_(map_index), val_(val), should_set_(should_set) - { } - - protected: - int - do_traverse(Traverse* traverse); - - bool - do_traverse_assignments(Traverse_assignments*) - { go_unreachable(); } - - Statement* - do_lower(Gogo*, Named_object*, Block*, Statement_inserter*); - - Bstatement* - do_get_backend(Translate_context*) - { go_unreachable(); } - - void - do_dump_statement(Ast_dump_context*) const; - - private: - // A reference to the map index which should be set or deleted. - Expression* map_index_; - // The value to add to the map. - Expression* val_; - // Whether or not to add the value. - Expression* should_set_; -}; - -// Traverse a map assignment. - -int -Map_assignment_statement::do_traverse(Traverse* traverse) -{ - if (this->traverse_expression(traverse, &this->map_index_) == TRAVERSE_EXIT - || this->traverse_expression(traverse, &this->val_) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - return this->traverse_expression(traverse, &this->should_set_); -} - -// Lower a map assignment to a function call. - -Statement* -Map_assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing, - Statement_inserter*) -{ - Location loc = this->location(); - - Map_index_expression* map_index = this->map_index_->map_index_expression(); - if (map_index == NULL) - { - this->report_error(_("expected map index on left hand side")); - return Statement::make_error_statement(loc); - } - Map_type* map_type = map_index->get_map_type(); - if (map_type == NULL) - return Statement::make_error_statement(loc); - - Block* b = new Block(enclosing, loc); - - // Evaluate the map first to get order of evaluation right. - // map_temp := m // we are evaluating m[k] = v, p - Temporary_statement* map_temp = Statement::make_temporary(map_type, - map_index->map(), - loc); - b->add_statement(map_temp); - - // var key_temp MAP_KEY_TYPE = k - Temporary_statement* key_temp = - Statement::make_temporary(map_type->key_type(), map_index->index(), loc); - b->add_statement(key_temp); - - // var val_temp MAP_VAL_TYPE = v - Temporary_statement* val_temp = - Statement::make_temporary(map_type->val_type(), this->val_, loc); - b->add_statement(val_temp); - - // var insert_temp bool = p - Temporary_statement* insert_temp = - Statement::make_temporary(Type::lookup_bool_type(), this->should_set_, - loc); - b->add_statement(insert_temp); - - // mapassign2(map_temp, &key_temp, &val_temp, p) - Expression* p1 = Expression::make_temporary_reference(map_temp, loc); - Expression* ref = Expression::make_temporary_reference(key_temp, loc); - Expression* p2 = Expression::make_unary(OPERATOR_AND, ref, loc); - ref = Expression::make_temporary_reference(val_temp, loc); - Expression* p3 = Expression::make_unary(OPERATOR_AND, ref, loc); - Expression* p4 = Expression::make_temporary_reference(insert_temp, loc); - Expression* call = Runtime::make_call(Runtime::MAPASSIGN2, loc, 4, - p1, p2, p3, p4); - Statement* s = Statement::make_statement(call, true); - b->add_statement(s); - - return Statement::make_block_statement(b, loc); -} - -// Dump the AST representation for a map assignment statement. - -void -Map_assignment_statement::do_dump_statement( - Ast_dump_context* ast_dump_context) const -{ - ast_dump_context->print_indent(); - ast_dump_context->dump_expression(this->map_index_); - ast_dump_context->ostream() << " = "; - ast_dump_context->dump_expression(this->val_); - ast_dump_context->ostream() << ", "; - ast_dump_context->dump_expression(this->should_set_); - ast_dump_context->ostream() << std::endl; -} - -// Make a statement which assigns a pair of entries to a map. - -Statement* -Statement::make_map_assignment(Expression* map_index, - Expression* val, Expression* should_set, - Location location) -{ - return new Map_assignment_statement(map_index, val, should_set, location); -} - -// A tuple assignment from a receive statement. - -class Tuple_receive_assignment_statement : public Statement -{ - public: - Tuple_receive_assignment_statement(Expression* val, Expression* closed, - Expression* channel, Location location) - : Statement(STATEMENT_TUPLE_RECEIVE_ASSIGNMENT, location), - val_(val), closed_(closed), channel_(channel) - { } - - protected: - int - do_traverse(Traverse* traverse); - - bool - do_traverse_assignments(Traverse_assignments*) - { go_unreachable(); } - - Statement* - do_lower(Gogo*, Named_object*, Block*, Statement_inserter*); - - Bstatement* - do_get_backend(Translate_context*) - { go_unreachable(); } - - void - do_dump_statement(Ast_dump_context*) const; - - private: - // Lvalue which receives the value from the channel. - Expression* val_; - // Lvalue which receives whether the channel is closed. - Expression* closed_; - // The channel on which we receive the value. - Expression* channel_; -}; - -// Traversal. - -int -Tuple_receive_assignment_statement::do_traverse(Traverse* traverse) -{ - if (this->traverse_expression(traverse, &this->val_) == TRAVERSE_EXIT - || this->traverse_expression(traverse, &this->closed_) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - return this->traverse_expression(traverse, &this->channel_); -} - -// Lower to a function call. - -Statement* -Tuple_receive_assignment_statement::do_lower(Gogo*, Named_object*, - Block* enclosing, - Statement_inserter*) -{ - Location loc = this->location(); - - Channel_type* channel_type = this->channel_->type()->channel_type(); - if (channel_type == NULL) - { - this->report_error(_("expected channel")); - return Statement::make_error_statement(loc); - } - if (!channel_type->may_receive()) - { - this->report_error(_("invalid receive on send-only channel")); - return Statement::make_error_statement(loc); - } - - Block* b = new Block(enclosing, loc); - - // Make sure that any subexpressions on the left hand side are - // evaluated in the right order. - Move_ordered_evals moe(b); - this->val_->traverse_subexpressions(&moe); - this->closed_->traverse_subexpressions(&moe); - - // var val_temp ELEMENT_TYPE - Temporary_statement* val_temp = - Statement::make_temporary(channel_type->element_type(), NULL, loc); - b->add_statement(val_temp); - - // var closed_temp bool - Temporary_statement* closed_temp = - Statement::make_temporary(Type::lookup_bool_type(), NULL, loc); - b->add_statement(closed_temp); - - // closed_temp = chanrecv2(type, channel, &val_temp) - Expression* td = Expression::make_type_descriptor(this->channel_->type(), - loc); - Temporary_reference_expression* ref = - Expression::make_temporary_reference(val_temp, loc); - Expression* p2 = Expression::make_unary(OPERATOR_AND, ref, loc); - Expression* call = Runtime::make_call(Runtime::CHANRECV2, - loc, 3, td, this->channel_, p2); - ref = Expression::make_temporary_reference(closed_temp, loc); - ref->set_is_lvalue(); - Statement* s = Statement::make_assignment(ref, call, loc); - b->add_statement(s); - - // val = val_temp - ref = Expression::make_temporary_reference(val_temp, loc); - s = Statement::make_assignment(this->val_, ref, loc); - b->add_statement(s); - - // closed = closed_temp - ref = Expression::make_temporary_reference(closed_temp, loc); - s = Statement::make_assignment(this->closed_, ref, loc); - b->add_statement(s); - - return Statement::make_block_statement(b, loc); -} - -// Dump the AST representation for a tuple receive statement. - -void -Tuple_receive_assignment_statement::do_dump_statement( - Ast_dump_context* ast_dump_context) const -{ - ast_dump_context->print_indent(); - ast_dump_context->dump_expression(this->val_); - ast_dump_context->ostream() << ", "; - ast_dump_context->dump_expression(this->closed_); - ast_dump_context->ostream() << " <- "; - ast_dump_context->dump_expression(this->channel_); - ast_dump_context->ostream() << std::endl; -} - -// Make a nonblocking receive statement. - -Statement* -Statement::make_tuple_receive_assignment(Expression* val, Expression* closed, - Expression* channel, - Location location) -{ - return new Tuple_receive_assignment_statement(val, closed, channel, - location); -} - -// An assignment to a pair of values from a type guard. This is a -// conditional type guard. v, ok = i.(type). - -class Tuple_type_guard_assignment_statement : public Statement -{ - public: - Tuple_type_guard_assignment_statement(Expression* val, Expression* ok, - Expression* expr, Type* type, - Location location) - : Statement(STATEMENT_TUPLE_TYPE_GUARD_ASSIGNMENT, location), - val_(val), ok_(ok), expr_(expr), type_(type) - { } - - protected: - int - do_traverse(Traverse*); - - bool - do_traverse_assignments(Traverse_assignments*) - { go_unreachable(); } - - Statement* - do_lower(Gogo*, Named_object*, Block*, Statement_inserter*); - - Bstatement* - do_get_backend(Translate_context*) - { go_unreachable(); } - - void - do_dump_statement(Ast_dump_context*) const; - - private: - Call_expression* - lower_to_type(Runtime::Function); - - void - lower_to_object_type(Block*, Runtime::Function); - - // The variable which recieves the converted value. - Expression* val_; - // The variable which receives the indication of success. - Expression* ok_; - // The expression being converted. - Expression* expr_; - // The type to which the expression is being converted. - Type* type_; -}; - -// Traverse a type guard tuple assignment. - -int -Tuple_type_guard_assignment_statement::do_traverse(Traverse* traverse) -{ - if (this->traverse_expression(traverse, &this->val_) == TRAVERSE_EXIT - || this->traverse_expression(traverse, &this->ok_) == TRAVERSE_EXIT - || this->traverse_type(traverse, this->type_) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - return this->traverse_expression(traverse, &this->expr_); -} - -// Lower to a function call. - -Statement* -Tuple_type_guard_assignment_statement::do_lower(Gogo*, Named_object*, - Block* enclosing, - Statement_inserter*) -{ - Location loc = this->location(); - - Type* expr_type = this->expr_->type(); - if (expr_type->interface_type() == NULL) - { - if (!expr_type->is_error() && !this->type_->is_error()) - this->report_error(_("type assertion only valid for interface types")); - return Statement::make_error_statement(loc); - } - - Block* b = new Block(enclosing, loc); - - // Make sure that any subexpressions on the left hand side are - // evaluated in the right order. - Move_ordered_evals moe(b); - this->val_->traverse_subexpressions(&moe); - this->ok_->traverse_subexpressions(&moe); - - bool expr_is_empty = expr_type->interface_type()->is_empty(); - Call_expression* call; - if (this->type_->interface_type() != NULL) - { - if (this->type_->interface_type()->is_empty()) - call = Runtime::make_call((expr_is_empty - ? Runtime::IFACEE2E2 - : Runtime::IFACEI2E2), - loc, 1, this->expr_); - else - call = this->lower_to_type(expr_is_empty - ? Runtime::IFACEE2I2 - : Runtime::IFACEI2I2); - } - else if (this->type_->points_to() != NULL) - call = this->lower_to_type(expr_is_empty - ? Runtime::IFACEE2T2P - : Runtime::IFACEI2T2P); - else - { - this->lower_to_object_type(b, - (expr_is_empty - ? Runtime::IFACEE2T2 - : Runtime::IFACEI2T2)); - call = NULL; - } - - if (call != NULL) - { - Expression* res = Expression::make_call_result(call, 0); - res = Expression::make_unsafe_cast(this->type_, res, loc); - Statement* s = Statement::make_assignment(this->val_, res, loc); - b->add_statement(s); - - res = Expression::make_call_result(call, 1); - s = Statement::make_assignment(this->ok_, res, loc); - b->add_statement(s); - } - - return Statement::make_block_statement(b, loc); -} - -// Lower a conversion to a non-empty interface type or a pointer type. - -Call_expression* -Tuple_type_guard_assignment_statement::lower_to_type(Runtime::Function code) -{ - Location loc = this->location(); - return Runtime::make_call(code, loc, 2, - Expression::make_type_descriptor(this->type_, loc), - this->expr_); -} - -// Lower a conversion to a non-interface non-pointer type. - -void -Tuple_type_guard_assignment_statement::lower_to_object_type( - Block* b, - Runtime::Function code) -{ - Location loc = this->location(); - - // var val_temp TYPE - Temporary_statement* val_temp = Statement::make_temporary(this->type_, - NULL, loc); - b->add_statement(val_temp); - - // ok = CODE(type_descriptor, expr, &val_temp) - Expression* p1 = Expression::make_type_descriptor(this->type_, loc); - Expression* ref = Expression::make_temporary_reference(val_temp, loc); - Expression* p3 = Expression::make_unary(OPERATOR_AND, ref, loc); - Expression* call = Runtime::make_call(code, loc, 3, p1, this->expr_, p3); - Statement* s = Statement::make_assignment(this->ok_, call, loc); - b->add_statement(s); - - // val = val_temp - ref = Expression::make_temporary_reference(val_temp, loc); - s = Statement::make_assignment(this->val_, ref, loc); - b->add_statement(s); -} - -// Dump the AST representation for a tuple type guard statement. - -void -Tuple_type_guard_assignment_statement::do_dump_statement( - Ast_dump_context* ast_dump_context) const -{ - ast_dump_context->print_indent(); - ast_dump_context->dump_expression(this->val_); - ast_dump_context->ostream() << ", "; - ast_dump_context->dump_expression(this->ok_); - ast_dump_context->ostream() << " = "; - ast_dump_context->dump_expression(this->expr_); - ast_dump_context->ostream() << " . "; - ast_dump_context->dump_type(this->type_); - ast_dump_context->ostream() << std::endl; -} - -// Make an assignment from a type guard to a pair of variables. - -Statement* -Statement::make_tuple_type_guard_assignment(Expression* val, Expression* ok, - Expression* expr, Type* type, - Location location) -{ - return new Tuple_type_guard_assignment_statement(val, ok, expr, type, - location); -} - -// An expression statement. - -class Expression_statement : public Statement -{ - public: - Expression_statement(Expression* expr, bool is_ignored) - : Statement(STATEMENT_EXPRESSION, expr->location()), - expr_(expr), is_ignored_(is_ignored) - { } - - Expression* - expr() - { return this->expr_; } - - protected: - int - do_traverse(Traverse* traverse) - { return this->traverse_expression(traverse, &this->expr_); } - - void - do_determine_types() - { this->expr_->determine_type_no_context(); } - - void - do_check_types(Gogo*); - - bool - do_may_fall_through() const; - - Bstatement* - do_get_backend(Translate_context* context); - - void - do_dump_statement(Ast_dump_context*) const; - - private: - Expression* expr_; - // Whether the value of this expression is being explicitly ignored. - bool is_ignored_; -}; - -// Check the types of an expression statement. The only check we do -// is to possibly give an error about discarding the value of the -// expression. - -void -Expression_statement::do_check_types(Gogo*) -{ - if (!this->is_ignored_) - this->expr_->discarding_value(); -} - -// An expression statement may fall through unless it is a call to a -// function which does not return. - -bool -Expression_statement::do_may_fall_through() const -{ - const Call_expression* call = this->expr_->call_expression(); - if (call != NULL) - { - const Expression* fn = call->fn(); - const Func_expression* fe = fn->func_expression(); - if (fe != NULL) - { - const Named_object* no = fe->named_object(); - - Function_type* fntype; - if (no->is_function()) - fntype = no->func_value()->type(); - else if (no->is_function_declaration()) - fntype = no->func_declaration_value()->type(); - else - fntype = NULL; - - // The builtin function panic does not return. - if (fntype != NULL && fntype->is_builtin() && no->name() == "panic") - return false; - } - } - return true; -} - -// Convert to backend representation. - -Bstatement* -Expression_statement::do_get_backend(Translate_context* context) -{ - tree expr_tree = this->expr_->get_tree(context); - return context->backend()->expression_statement(tree_to_expr(expr_tree)); -} - -// Dump the AST representation for an expression statement - -void -Expression_statement::do_dump_statement(Ast_dump_context* ast_dump_context) - const -{ - ast_dump_context->print_indent(); - ast_dump_context->dump_expression(expr_); - ast_dump_context->ostream() << std::endl; -} - -// Make an expression statement from an Expression. - -Statement* -Statement::make_statement(Expression* expr, bool is_ignored) -{ - return new Expression_statement(expr, is_ignored); -} - -// A block statement--a list of statements which may include variable -// definitions. - -class Block_statement : public Statement -{ - public: - Block_statement(Block* block, Location location) - : Statement(STATEMENT_BLOCK, location), - block_(block) - { } - - protected: - int - do_traverse(Traverse* traverse) - { return this->block_->traverse(traverse); } - - void - do_determine_types() - { this->block_->determine_types(); } - - bool - do_may_fall_through() const - { return this->block_->may_fall_through(); } - - Bstatement* - do_get_backend(Translate_context* context); - - void - do_dump_statement(Ast_dump_context*) const; - - private: - Block* block_; -}; - -// Convert a block to the backend representation of a statement. - -Bstatement* -Block_statement::do_get_backend(Translate_context* context) -{ - Bblock* bblock = this->block_->get_backend(context); - return context->backend()->block_statement(bblock); -} - -// Dump the AST for a block statement - -void -Block_statement::do_dump_statement(Ast_dump_context*) const -{ - // block statement braces are dumped when traversing. -} - -// Make a block statement. - -Statement* -Statement::make_block_statement(Block* block, Location location) -{ - return new Block_statement(block, location); -} - -// An increment or decrement statement. - -class Inc_dec_statement : public Statement -{ - public: - Inc_dec_statement(bool is_inc, Expression* expr) - : Statement(STATEMENT_INCDEC, expr->location()), - expr_(expr), is_inc_(is_inc) - { } - - protected: - int - do_traverse(Traverse* traverse) - { return this->traverse_expression(traverse, &this->expr_); } - - bool - do_traverse_assignments(Traverse_assignments*) - { go_unreachable(); } - - Statement* - do_lower(Gogo*, Named_object*, Block*, Statement_inserter*); - - Bstatement* - do_get_backend(Translate_context*) - { go_unreachable(); } - - void - do_dump_statement(Ast_dump_context*) const; - - private: - // The l-value to increment or decrement. - Expression* expr_; - // Whether to increment or decrement. - bool is_inc_; -}; - -// Lower to += or -=. - -Statement* -Inc_dec_statement::do_lower(Gogo*, Named_object*, Block*, Statement_inserter*) -{ - Location loc = this->location(); - - mpz_t oval; - mpz_init_set_ui(oval, 1UL); - Expression* oexpr = Expression::make_integer(&oval, NULL, loc); - mpz_clear(oval); - - Operator op = this->is_inc_ ? OPERATOR_PLUSEQ : OPERATOR_MINUSEQ; - return Statement::make_assignment_operation(op, this->expr_, oexpr, loc); -} - -// Dump the AST representation for a inc/dec statement. - -void -Inc_dec_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const -{ - ast_dump_context->print_indent(); - ast_dump_context->dump_expression(expr_); - ast_dump_context->ostream() << (is_inc_? "++": "--") << std::endl; -} - -// Make an increment statement. - -Statement* -Statement::make_inc_statement(Expression* expr) -{ - return new Inc_dec_statement(true, expr); -} - -// Make a decrement statement. - -Statement* -Statement::make_dec_statement(Expression* expr) -{ - return new Inc_dec_statement(false, expr); -} - -// Class Thunk_statement. This is the base class for go and defer -// statements. - -// Constructor. - -Thunk_statement::Thunk_statement(Statement_classification classification, - Call_expression* call, - Location location) - : Statement(classification, location), - call_(call), struct_type_(NULL) -{ -} - -// Return whether this is a simple statement which does not require a -// thunk. - -bool -Thunk_statement::is_simple(Function_type* fntype) const -{ - // We need a thunk to call a method, or to pass a variable number of - // arguments. - if (fntype->is_method() || fntype->is_varargs()) - return false; - - // A defer statement requires a thunk to set up for whether the - // function can call recover. - if (this->classification() == STATEMENT_DEFER) - return false; - - // We can only permit a single parameter of pointer type. - const Typed_identifier_list* parameters = fntype->parameters(); - if (parameters != NULL - && (parameters->size() > 1 - || (parameters->size() == 1 - && parameters->begin()->type()->points_to() == NULL))) - return false; - - // If the function returns multiple values, or returns a type other - // than integer, floating point, or pointer, then it may get a - // hidden first parameter, in which case we need the more - // complicated approach. This is true even though we are going to - // ignore the return value. - const Typed_identifier_list* results = fntype->results(); - if (results != NULL - && (results->size() > 1 - || (results->size() == 1 - && !results->begin()->type()->is_basic_type() - && results->begin()->type()->points_to() == NULL))) - return false; - - // If this calls something which is not a simple function, then we - // need a thunk. - Expression* fn = this->call_->call_expression()->fn(); - if (fn->interface_field_reference_expression() != NULL) - return false; - - return true; -} - -// Traverse a thunk statement. - -int -Thunk_statement::do_traverse(Traverse* traverse) -{ - return this->traverse_expression(traverse, &this->call_); -} - -// We implement traverse_assignment for a thunk statement because it -// effectively copies the function call. - -bool -Thunk_statement::do_traverse_assignments(Traverse_assignments* tassign) -{ - Expression* fn = this->call_->call_expression()->fn(); - Expression* fn2 = fn; - tassign->value(&fn2, true, false); - return true; -} - -// Determine types in a thunk statement. - -void -Thunk_statement::do_determine_types() -{ - this->call_->determine_type_no_context(); - - // Now that we know the types of the call, build the struct used to - // pass parameters. - Call_expression* ce = this->call_->call_expression(); - if (ce == NULL) - return; - Function_type* fntype = ce->get_function_type(); - if (fntype != NULL && !this->is_simple(fntype)) - this->struct_type_ = this->build_struct(fntype); -} - -// Check types in a thunk statement. - -void -Thunk_statement::do_check_types(Gogo*) -{ - if (!this->call_->discarding_value()) - return; - Call_expression* ce = this->call_->call_expression(); - if (ce == NULL) - { - if (!this->call_->is_error_expression()) - this->report_error("expected call expression"); - return; - } -} - -// The Traverse class used to find and simplify thunk statements. - -class Simplify_thunk_traverse : public Traverse -{ - public: - Simplify_thunk_traverse(Gogo* gogo) - : Traverse(traverse_functions | traverse_blocks), - gogo_(gogo), function_(NULL) - { } - - int - function(Named_object*); - - int - block(Block*); - - private: - // General IR. - Gogo* gogo_; - // The function we are traversing. - Named_object* function_; -}; - -// Keep track of the current function while looking for thunks. - -int -Simplify_thunk_traverse::function(Named_object* no) -{ - go_assert(this->function_ == NULL); - this->function_ = no; - int t = no->func_value()->traverse(this); - this->function_ = NULL; - if (t == TRAVERSE_EXIT) - return t; - return TRAVERSE_SKIP_COMPONENTS; -} - -// Look for thunks in a block. - -int -Simplify_thunk_traverse::block(Block* b) -{ - // The parser ensures that thunk statements always appear at the end - // of a block. - if (b->statements()->size() < 1) - return TRAVERSE_CONTINUE; - Thunk_statement* stat = b->statements()->back()->thunk_statement(); - if (stat == NULL) - return TRAVERSE_CONTINUE; - if (stat->simplify_statement(this->gogo_, this->function_, b)) - return TRAVERSE_SKIP_COMPONENTS; - return TRAVERSE_CONTINUE; -} - -// Simplify all thunk statements. - -void -Gogo::simplify_thunk_statements() -{ - Simplify_thunk_traverse thunk_traverse(this); - this->traverse(&thunk_traverse); -} - -// Return true if the thunk function is a constant, which means that -// it does not need to be passed to the thunk routine. - -bool -Thunk_statement::is_constant_function() const -{ - Call_expression* ce = this->call_->call_expression(); - Function_type* fntype = ce->get_function_type(); - if (fntype == NULL) - { - go_assert(saw_errors()); - return false; - } - if (fntype->is_builtin()) - return true; - Expression* fn = ce->fn(); - if (fn->func_expression() != NULL) - return fn->func_expression()->closure() == NULL; - if (fn->interface_field_reference_expression() != NULL) - return true; - return false; -} - -// Simplify complex thunk statements into simple ones. A complicated -// thunk statement is one which takes anything other than zero -// parameters or a single pointer parameter. We rewrite it into code -// which allocates a struct, stores the parameter values into the -// struct, and does a simple go or defer statement which passes the -// struct to a thunk. The thunk does the real call. - -bool -Thunk_statement::simplify_statement(Gogo* gogo, Named_object* function, - Block* block) -{ - if (this->classification() == STATEMENT_ERROR) - return false; - if (this->call_->is_error_expression()) - return false; - - if (this->classification() == STATEMENT_DEFER) - { - // Make sure that the defer stack exists for the function. We - // will use when converting this statement to the backend - // representation, but we want it to exist when we start - // converting the function. - function->func_value()->defer_stack(this->location()); - } - - Call_expression* ce = this->call_->call_expression(); - Function_type* fntype = ce->get_function_type(); - if (fntype == NULL) - { - go_assert(saw_errors()); - this->set_is_error(); - return false; - } - if (this->is_simple(fntype)) - return false; - - Expression* fn = ce->fn(); - Interface_field_reference_expression* interface_method = - fn->interface_field_reference_expression(); - - Location location = this->location(); - - std::string thunk_name = Gogo::thunk_name(); - - // Build the thunk. - this->build_thunk(gogo, thunk_name); - - // Generate code to call the thunk. - - // Get the values to store into the struct which is the single - // argument to the thunk. - - Expression_list* vals = new Expression_list(); - if (!this->is_constant_function()) - vals->push_back(fn); - - if (interface_method != NULL) - vals->push_back(interface_method->expr()); - - if (ce->args() != NULL) - { - for (Expression_list::const_iterator p = ce->args()->begin(); - p != ce->args()->end(); - ++p) - vals->push_back(*p); - } - - // Build the struct. - Expression* constructor = - Expression::make_struct_composite_literal(this->struct_type_, vals, - location); - - // Allocate the initialized struct on the heap. - constructor = Expression::make_heap_composite(constructor, location); - - // Look up the thunk. - Named_object* named_thunk = gogo->lookup(thunk_name, NULL); - go_assert(named_thunk != NULL && named_thunk->is_function()); - - // Build the call. - Expression* func = Expression::make_func_reference(named_thunk, NULL, - location); - Expression_list* params = new Expression_list(); - params->push_back(constructor); - Call_expression* call = Expression::make_call(func, params, false, location); - - // Build the simple go or defer statement. - Statement* s; - if (this->classification() == STATEMENT_GO) - s = Statement::make_go_statement(call, location); - else if (this->classification() == STATEMENT_DEFER) - s = Statement::make_defer_statement(call, location); - else - go_unreachable(); - - // The current block should end with the go statement. - go_assert(block->statements()->size() >= 1); - go_assert(block->statements()->back() == this); - block->replace_statement(block->statements()->size() - 1, s); - - // We already ran the determine_types pass, so we need to run it now - // for the new statement. - s->determine_types(); - - // Sanity check. - gogo->check_types_in_block(block); - - // Return true to tell the block not to keep looking at statements. - return true; -} - -// Set the name to use for thunk parameter N. - -void -Thunk_statement::thunk_field_param(int n, char* buf, size_t buflen) -{ - snprintf(buf, buflen, "a%d", n); -} - -// Build a new struct type to hold the parameters for a complicated -// thunk statement. FNTYPE is the type of the function call. - -Struct_type* -Thunk_statement::build_struct(Function_type* fntype) -{ - Location location = this->location(); - - Struct_field_list* fields = new Struct_field_list(); - - Call_expression* ce = this->call_->call_expression(); - Expression* fn = ce->fn(); - - if (!this->is_constant_function()) - { - // The function to call. - fields->push_back(Struct_field(Typed_identifier("fn", fntype, - location))); - } - - // If this thunk statement calls a method on an interface, we pass - // the interface object to the thunk. - Interface_field_reference_expression* interface_method = - fn->interface_field_reference_expression(); - if (interface_method != NULL) - { - Typed_identifier tid("object", interface_method->expr()->type(), - location); - fields->push_back(Struct_field(tid)); - } - - // The predeclared recover function has no argument. However, we - // add an argument when building recover thunks. Handle that here. - if (ce->is_recover_call()) - { - fields->push_back(Struct_field(Typed_identifier("can_recover", - Type::lookup_bool_type(), - location))); - } - - const Expression_list* args = ce->args(); - if (args != NULL) - { - int i = 0; - for (Expression_list::const_iterator p = args->begin(); - p != args->end(); - ++p, ++i) - { - char buf[50]; - this->thunk_field_param(i, buf, sizeof buf); - fields->push_back(Struct_field(Typed_identifier(buf, (*p)->type(), - location))); - } - } - - return Type::make_struct_type(fields, location); -} - -// Build the thunk we are going to call. This is a brand new, albeit -// artificial, function. - -void -Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name) -{ - Location location = this->location(); - - Call_expression* ce = this->call_->call_expression(); - - bool may_call_recover = false; - if (this->classification() == STATEMENT_DEFER) - { - Func_expression* fn = ce->fn()->func_expression(); - if (fn == NULL) - may_call_recover = true; - else - { - const Named_object* no = fn->named_object(); - if (!no->is_function()) - may_call_recover = true; - else - may_call_recover = no->func_value()->calls_recover(); - } - } - - // Build the type of the thunk. The thunk takes a single parameter, - // which is a pointer to the special structure we build. - const char* const parameter_name = "__go_thunk_parameter"; - Typed_identifier_list* thunk_parameters = new Typed_identifier_list(); - Type* pointer_to_struct_type = Type::make_pointer_type(this->struct_type_); - thunk_parameters->push_back(Typed_identifier(parameter_name, - pointer_to_struct_type, - location)); - - Typed_identifier_list* thunk_results = NULL; - if (may_call_recover) - { - // When deferring a function which may call recover, add a - // return value, to disable tail call optimizations which will - // break the way we check whether recover is permitted. - thunk_results = new Typed_identifier_list(); - thunk_results->push_back(Typed_identifier("", Type::lookup_bool_type(), - location)); - } - - Function_type* thunk_type = Type::make_function_type(NULL, thunk_parameters, - thunk_results, - location); - - // Start building the thunk. - Named_object* function = gogo->start_function(thunk_name, thunk_type, true, - location); - - gogo->start_block(location); - - // For a defer statement, start with a call to - // __go_set_defer_retaddr. */ - Label* retaddr_label = NULL; - if (may_call_recover) - { - retaddr_label = gogo->add_label_reference("retaddr", location, false); - Expression* arg = Expression::make_label_addr(retaddr_label, location); - Expression* call = Runtime::make_call(Runtime::SET_DEFER_RETADDR, - location, 1, arg); - - // This is a hack to prevent the middle-end from deleting the - // label. - gogo->start_block(location); - gogo->add_statement(Statement::make_goto_statement(retaddr_label, - location)); - Block* then_block = gogo->finish_block(location); - then_block->determine_types(); - - Statement* s = Statement::make_if_statement(call, then_block, NULL, - location); - s->determine_types(); - gogo->add_statement(s); - } - - // Get a reference to the parameter. - Named_object* named_parameter = gogo->lookup(parameter_name, NULL); - go_assert(named_parameter != NULL && named_parameter->is_variable()); - - // Build the call. Note that the field names are the same as the - // ones used in build_struct. - Expression* thunk_parameter = Expression::make_var_reference(named_parameter, - location); - thunk_parameter = Expression::make_unary(OPERATOR_MULT, thunk_parameter, - location); - - Interface_field_reference_expression* interface_method = - ce->fn()->interface_field_reference_expression(); - - Expression* func_to_call; - unsigned int next_index; - if (this->is_constant_function()) - { - func_to_call = ce->fn(); - next_index = 0; - } - else - { - func_to_call = Expression::make_field_reference(thunk_parameter, - 0, location); - next_index = 1; - } - - if (interface_method != NULL) - { - // The main program passes the interface object. - go_assert(next_index == 0); - Expression* r = Expression::make_field_reference(thunk_parameter, 0, - location); - const std::string& name(interface_method->name()); - func_to_call = Expression::make_interface_field_reference(r, name, - location); - next_index = 1; - } - - Expression_list* call_params = new Expression_list(); - const Struct_field_list* fields = this->struct_type_->fields(); - Struct_field_list::const_iterator p = fields->begin(); - for (unsigned int i = 0; i < next_index; ++i) - ++p; - bool is_recover_call = ce->is_recover_call(); - Expression* recover_arg = NULL; - for (; p != fields->end(); ++p, ++next_index) - { - Expression* thunk_param = Expression::make_var_reference(named_parameter, - location); - thunk_param = Expression::make_unary(OPERATOR_MULT, thunk_param, - location); - Expression* param = Expression::make_field_reference(thunk_param, - next_index, - location); - if (!is_recover_call) - call_params->push_back(param); - else - { - go_assert(call_params->empty()); - recover_arg = param; - } - } - - if (call_params->empty()) - { - delete call_params; - call_params = NULL; - } - - Call_expression* call = Expression::make_call(func_to_call, call_params, - false, location); - - // This call expression was already lowered before entering the - // thunk statement. Don't try to lower varargs again, as that will - // cause confusion for, e.g., method calls which already have a - // receiver parameter. - call->set_varargs_are_lowered(); - - Statement* call_statement = Statement::make_statement(call, true); - - gogo->add_statement(call_statement); - - // If this is a defer statement, the label comes immediately after - // the call. - if (may_call_recover) - { - gogo->add_label_definition("retaddr", location); - - Expression_list* vals = new Expression_list(); - vals->push_back(Expression::make_boolean(false, location)); - gogo->add_statement(Statement::make_return_statement(vals, location)); - } - - Block* b = gogo->finish_block(location); - - gogo->add_block(b, location); - - gogo->lower_block(function, b); - - // We already ran the determine_types pass, so we need to run it - // just for the call statement now. The other types are known. - call_statement->determine_types(); - - if (may_call_recover || recover_arg != NULL) - { - // Dig up the call expression, which may have been changed - // during lowering. - go_assert(call_statement->classification() == STATEMENT_EXPRESSION); - Expression_statement* es = - static_cast<Expression_statement*>(call_statement); - Call_expression* ce = es->expr()->call_expression(); - if (ce == NULL) - go_assert(saw_errors()); - else - { - if (may_call_recover) - ce->set_is_deferred(); - if (recover_arg != NULL) - ce->set_recover_arg(recover_arg); - } - } - - // That is all the thunk has to do. - gogo->finish_function(location); -} - -// Get the function and argument expressions. - -bool -Thunk_statement::get_fn_and_arg(Expression** pfn, Expression** parg) -{ - if (this->call_->is_error_expression()) - return false; - - Call_expression* ce = this->call_->call_expression(); - - *pfn = ce->fn(); - - const Expression_list* args = ce->args(); - if (args == NULL || args->empty()) - *parg = Expression::make_nil(this->location()); - else - { - go_assert(args->size() == 1); - *parg = args->front(); - } - - return true; -} - -// Class Go_statement. - -Bstatement* -Go_statement::do_get_backend(Translate_context* context) -{ - Expression* fn; - Expression* arg; - if (!this->get_fn_and_arg(&fn, &arg)) - return context->backend()->error_statement(); - - Expression* call = Runtime::make_call(Runtime::GO, this->location(), 2, - fn, arg); - tree call_tree = call->get_tree(context); - Bexpression* call_bexpr = tree_to_expr(call_tree); - return context->backend()->expression_statement(call_bexpr); -} - -// Dump the AST representation for go statement. - -void -Go_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const -{ - ast_dump_context->print_indent(); - ast_dump_context->ostream() << "go "; - ast_dump_context->dump_expression(this->call()); - ast_dump_context->ostream() << std::endl; -} - -// Make a go statement. - -Statement* -Statement::make_go_statement(Call_expression* call, Location location) -{ - return new Go_statement(call, location); -} - -// Class Defer_statement. - -Bstatement* -Defer_statement::do_get_backend(Translate_context* context) -{ - Expression* fn; - Expression* arg; - if (!this->get_fn_and_arg(&fn, &arg)) - return context->backend()->error_statement(); - - Location loc = this->location(); - Expression* ds = context->function()->func_value()->defer_stack(loc); - - Expression* call = Runtime::make_call(Runtime::DEFER, loc, 3, - ds, fn, arg); - tree call_tree = call->get_tree(context); - Bexpression* call_bexpr = tree_to_expr(call_tree); - return context->backend()->expression_statement(call_bexpr); -} - -// Dump the AST representation for defer statement. - -void -Defer_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const -{ - ast_dump_context->print_indent(); - ast_dump_context->ostream() << "defer "; - ast_dump_context->dump_expression(this->call()); - ast_dump_context->ostream() << std::endl; -} - -// Make a defer statement. - -Statement* -Statement::make_defer_statement(Call_expression* call, - Location location) -{ - return new Defer_statement(call, location); -} - -// Class Return_statement. - -// Traverse assignments. We treat each return value as a top level -// RHS in an expression. - -bool -Return_statement::do_traverse_assignments(Traverse_assignments* tassign) -{ - Expression_list* vals = this->vals_; - if (vals != NULL) - { - for (Expression_list::iterator p = vals->begin(); - p != vals->end(); - ++p) - tassign->value(&*p, true, true); - } - return true; -} - -// Lower a return statement. If we are returning a function call -// which returns multiple values which match the current function, -// split up the call's results. If the return statement lists -// explicit values, implement this statement by assigning the values -// to the result variables and change this statement to a naked -// return. This lets panic/recover work correctly. - -Statement* -Return_statement::do_lower(Gogo*, Named_object* function, Block* enclosing, - Statement_inserter*) -{ - if (this->is_lowered_) - return this; - - Expression_list* vals = this->vals_; - this->vals_ = NULL; - this->is_lowered_ = true; - - Location loc = this->location(); - - size_t vals_count = vals == NULL ? 0 : vals->size(); - Function::Results* results = function->func_value()->result_variables(); - size_t results_count = results == NULL ? 0 : results->size(); - - if (vals_count == 0) - { - if (results_count > 0 && !function->func_value()->results_are_named()) - { - this->report_error(_("not enough arguments to return")); - return this; - } - return this; - } - - if (results_count == 0) - { - this->report_error(_("return with value in function " - "with no return type")); - return this; - } - - // If the current function has multiple return values, and we are - // returning a single call expression, split up the call expression. - if (results_count > 1 - && vals->size() == 1 - && vals->front()->call_expression() != NULL) - { - Call_expression* call = vals->front()->call_expression(); - delete vals; - vals = new Expression_list; - for (size_t i = 0; i < results_count; ++i) - vals->push_back(Expression::make_call_result(call, i)); - vals_count = results_count; - } - - if (vals_count < results_count) - { - this->report_error(_("not enough arguments to return")); - return this; - } - - if (vals_count > results_count) - { - this->report_error(_("too many values in return statement")); - return this; - } - - Block* b = new Block(enclosing, loc); - - Expression_list* lhs = new Expression_list(); - Expression_list* rhs = new Expression_list(); - - Expression_list::const_iterator pe = vals->begin(); - int i = 1; - for (Function::Results::const_iterator pr = results->begin(); - pr != results->end(); - ++pr, ++pe, ++i) - { - Named_object* rv = *pr; - Expression* e = *pe; - - // Check types now so that we give a good error message. The - // result type is known. We determine the expression type - // early. - - Type *rvtype = rv->result_var_value()->type(); - Type_context type_context(rvtype, false); - e->determine_type(&type_context); - - std::string reason; - bool ok; - if (this->are_hidden_fields_ok_) - ok = Type::are_assignable_hidden_ok(rvtype, e->type(), &reason); - else - ok = Type::are_assignable(rvtype, e->type(), &reason); - if (ok) - { - Expression* ve = Expression::make_var_reference(rv, e->location()); - lhs->push_back(ve); - rhs->push_back(e); - } - else - { - if (reason.empty()) - error_at(e->location(), "incompatible type for return value %d", i); - else - error_at(e->location(), - "incompatible type for return value %d (%s)", - i, reason.c_str()); - } - } - go_assert(lhs->size() == rhs->size()); - - if (lhs->empty()) - ; - else if (lhs->size() == 1) - { - Statement* s = Statement::make_assignment(lhs->front(), rhs->front(), - loc); - if (this->are_hidden_fields_ok_) - { - Assignment_statement* as = static_cast<Assignment_statement*>(s); - as->set_hidden_fields_are_ok(); - } - b->add_statement(s); - delete lhs; - delete rhs; - } - else - { - Statement* s = Statement::make_tuple_assignment(lhs, rhs, loc); - if (this->are_hidden_fields_ok_) - { - Tuple_assignment_statement* tas = - static_cast<Tuple_assignment_statement*>(s); - tas->set_hidden_fields_are_ok(); - } - b->add_statement(s); - } - - b->add_statement(this); - - delete vals; - - return Statement::make_block_statement(b, loc); -} - -// Convert a return statement to the backend representation. - -Bstatement* -Return_statement::do_get_backend(Translate_context* context) -{ - Location loc = this->location(); - - Function* function = context->function()->func_value(); - tree fndecl = function->get_decl(); - - Function::Results* results = function->result_variables(); - std::vector<Bexpression*> retvals; - if (results != NULL && !results->empty()) - { - retvals.reserve(results->size()); - for (Function::Results::const_iterator p = results->begin(); - p != results->end(); - p++) - { - Expression* vr = Expression::make_var_reference(*p, loc); - retvals.push_back(tree_to_expr(vr->get_tree(context))); - } - } - - return context->backend()->return_statement(tree_to_function(fndecl), - retvals, loc); -} - -// Dump the AST representation for a return statement. - -void -Return_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const -{ - ast_dump_context->print_indent(); - ast_dump_context->ostream() << "return " ; - ast_dump_context->dump_expression_list(this->vals_); - ast_dump_context->ostream() << std::endl; -} - -// Make a return statement. - -Return_statement* -Statement::make_return_statement(Expression_list* vals, - Location location) -{ - return new Return_statement(vals, location); -} - -// A break or continue statement. - -class Bc_statement : public Statement -{ - public: - Bc_statement(bool is_break, Unnamed_label* label, Location location) - : Statement(STATEMENT_BREAK_OR_CONTINUE, location), - label_(label), is_break_(is_break) - { } - - bool - is_break() const - { return this->is_break_; } - - protected: - int - do_traverse(Traverse*) - { return TRAVERSE_CONTINUE; } - - bool - do_may_fall_through() const - { return false; } - - Bstatement* - do_get_backend(Translate_context* context) - { return this->label_->get_goto(context, this->location()); } - - void - do_dump_statement(Ast_dump_context*) const; - - private: - // The label that this branches to. - Unnamed_label* label_; - // True if this is "break", false if it is "continue". - bool is_break_; -}; - -// Dump the AST representation for a break/continue statement - -void -Bc_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const -{ - ast_dump_context->print_indent(); - ast_dump_context->ostream() << (this->is_break_ ? "break" : "continue"); - if (this->label_ != NULL) - { - ast_dump_context->ostream() << " "; - ast_dump_context->dump_label_name(this->label_); - } - ast_dump_context->ostream() << std::endl; -} - -// Make a break statement. - -Statement* -Statement::make_break_statement(Unnamed_label* label, Location location) -{ - return new Bc_statement(true, label, location); -} - -// Make a continue statement. - -Statement* -Statement::make_continue_statement(Unnamed_label* label, - Location location) -{ - return new Bc_statement(false, label, location); -} - -// A goto statement. - -class Goto_statement : public Statement -{ - public: - Goto_statement(Label* label, Location location) - : Statement(STATEMENT_GOTO, location), - label_(label) - { } - - protected: - int - do_traverse(Traverse*) - { return TRAVERSE_CONTINUE; } - - void - do_check_types(Gogo*); - - bool - do_may_fall_through() const - { return false; } - - Bstatement* - do_get_backend(Translate_context*); - - void - do_dump_statement(Ast_dump_context*) const; - - private: - Label* label_; -}; - -// Check types for a label. There aren't any types per se, but we use -// this to give an error if the label was never defined. - -void -Goto_statement::do_check_types(Gogo*) -{ - if (!this->label_->is_defined()) - { - error_at(this->location(), "reference to undefined label %qs", - Gogo::message_name(this->label_->name()).c_str()); - this->set_is_error(); - } -} - -// Convert the goto statement to the backend representation. - -Bstatement* -Goto_statement::do_get_backend(Translate_context* context) -{ - Blabel* blabel = this->label_->get_backend_label(context); - return context->backend()->goto_statement(blabel, this->location()); -} - -// Dump the AST representation for a goto statement. - -void -Goto_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const -{ - ast_dump_context->print_indent(); - ast_dump_context->ostream() << "goto " << this->label_->name() << std::endl; -} - -// Make a goto statement. - -Statement* -Statement::make_goto_statement(Label* label, Location location) -{ - return new Goto_statement(label, location); -} - -// A goto statement to an unnamed label. - -class Goto_unnamed_statement : public Statement -{ - public: - Goto_unnamed_statement(Unnamed_label* label, Location location) - : Statement(STATEMENT_GOTO_UNNAMED, location), - label_(label) - { } - - protected: - int - do_traverse(Traverse*) - { return TRAVERSE_CONTINUE; } - - bool - do_may_fall_through() const - { return false; } - - Bstatement* - do_get_backend(Translate_context* context) - { return this->label_->get_goto(context, this->location()); } - - void - do_dump_statement(Ast_dump_context*) const; - - private: - Unnamed_label* label_; -}; - -// Dump the AST representation for an unnamed goto statement - -void -Goto_unnamed_statement::do_dump_statement( - Ast_dump_context* ast_dump_context) const -{ - ast_dump_context->print_indent(); - ast_dump_context->ostream() << "goto "; - ast_dump_context->dump_label_name(this->label_); - ast_dump_context->ostream() << std::endl; -} - -// Make a goto statement to an unnamed label. - -Statement* -Statement::make_goto_unnamed_statement(Unnamed_label* label, - Location location) -{ - return new Goto_unnamed_statement(label, location); -} - -// Class Label_statement. - -// Traversal. - -int -Label_statement::do_traverse(Traverse*) -{ - return TRAVERSE_CONTINUE; -} - -// Return the backend representation of the statement defining this -// label. - -Bstatement* -Label_statement::do_get_backend(Translate_context* context) -{ - Blabel* blabel = this->label_->get_backend_label(context); - return context->backend()->label_definition_statement(blabel); -} - -// Dump the AST for a label definition statement. - -void -Label_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const -{ - ast_dump_context->print_indent(); - ast_dump_context->ostream() << this->label_->name() << ":" << std::endl; -} - -// Make a label statement. - -Statement* -Statement::make_label_statement(Label* label, Location location) -{ - return new Label_statement(label, location); -} - -// An unnamed label statement. - -class Unnamed_label_statement : public Statement -{ - public: - Unnamed_label_statement(Unnamed_label* label) - : Statement(STATEMENT_UNNAMED_LABEL, label->location()), - label_(label) - { } - - protected: - int - do_traverse(Traverse*) - { return TRAVERSE_CONTINUE; } - - Bstatement* - do_get_backend(Translate_context* context) - { return this->label_->get_definition(context); } - - void - do_dump_statement(Ast_dump_context*) const; - - private: - // The label. - Unnamed_label* label_; -}; - -// Dump the AST representation for an unnamed label definition statement. - -void -Unnamed_label_statement::do_dump_statement(Ast_dump_context* ast_dump_context) - const -{ - ast_dump_context->print_indent(); - ast_dump_context->dump_label_name(this->label_); - ast_dump_context->ostream() << ":" << std::endl; -} - -// Make an unnamed label statement. - -Statement* -Statement::make_unnamed_label_statement(Unnamed_label* label) -{ - return new Unnamed_label_statement(label); -} - -// An if statement. - -class If_statement : public Statement -{ - public: - If_statement(Expression* cond, Block* then_block, Block* else_block, - Location location) - : Statement(STATEMENT_IF, location), - cond_(cond), then_block_(then_block), else_block_(else_block) - { } - - protected: - int - do_traverse(Traverse*); - - void - do_determine_types(); - - void - do_check_types(Gogo*); - - bool - do_may_fall_through() const; - - Bstatement* - do_get_backend(Translate_context*); - - void - do_dump_statement(Ast_dump_context*) const; - - private: - Expression* cond_; - Block* then_block_; - Block* else_block_; -}; - -// Traversal. - -int -If_statement::do_traverse(Traverse* traverse) -{ - if (this->traverse_expression(traverse, &this->cond_) == TRAVERSE_EXIT - || this->then_block_->traverse(traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - if (this->else_block_ != NULL) - { - if (this->else_block_->traverse(traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - return TRAVERSE_CONTINUE; -} - -void -If_statement::do_determine_types() -{ - Type_context context(Type::lookup_bool_type(), false); - this->cond_->determine_type(&context); - this->then_block_->determine_types(); - if (this->else_block_ != NULL) - this->else_block_->determine_types(); -} - -// Check types. - -void -If_statement::do_check_types(Gogo*) -{ - Type* type = this->cond_->type(); - if (type->is_error()) - this->set_is_error(); - else if (!type->is_boolean_type()) - this->report_error(_("expected boolean expression")); -} - -// Whether the overall statement may fall through. - -bool -If_statement::do_may_fall_through() const -{ - return (this->else_block_ == NULL - || this->then_block_->may_fall_through() - || this->else_block_->may_fall_through()); -} - -// Get the backend representation. - -Bstatement* -If_statement::do_get_backend(Translate_context* context) -{ - go_assert(this->cond_->type()->is_boolean_type() - || this->cond_->type()->is_error()); - tree cond_tree = this->cond_->get_tree(context); - Bexpression* cond_expr = tree_to_expr(cond_tree); - Bblock* then_block = this->then_block_->get_backend(context); - Bblock* else_block = (this->else_block_ == NULL - ? NULL - : this->else_block_->get_backend(context)); - return context->backend()->if_statement(cond_expr, then_block, - else_block, this->location()); -} - -// Dump the AST representation for an if statement - -void -If_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const -{ - ast_dump_context->print_indent(); - ast_dump_context->ostream() << "if "; - ast_dump_context->dump_expression(this->cond_); - ast_dump_context->ostream() << std::endl; - if (ast_dump_context->dump_subblocks()) - { - ast_dump_context->dump_block(this->then_block_); - if (this->else_block_ != NULL) - { - ast_dump_context->print_indent(); - ast_dump_context->ostream() << "else" << std::endl; - ast_dump_context->dump_block(this->else_block_); - } - } -} - -// Make an if statement. - -Statement* -Statement::make_if_statement(Expression* cond, Block* then_block, - Block* else_block, Location location) -{ - return new If_statement(cond, then_block, else_block, location); -} - -// Class Case_clauses::Hash_integer_value. - -class Case_clauses::Hash_integer_value -{ - public: - size_t - operator()(Expression*) const; -}; - -size_t -Case_clauses::Hash_integer_value::operator()(Expression* pe) const -{ - Numeric_constant nc; - mpz_t ival; - if (!pe->numeric_constant_value(&nc) || !nc.to_int(&ival)) - go_unreachable(); - size_t ret = mpz_get_ui(ival); - mpz_clear(ival); - return ret; -} - -// Class Case_clauses::Eq_integer_value. - -class Case_clauses::Eq_integer_value -{ - public: - bool - operator()(Expression*, Expression*) const; -}; - -bool -Case_clauses::Eq_integer_value::operator()(Expression* a, Expression* b) const -{ - Numeric_constant anc; - mpz_t aval; - Numeric_constant bnc; - mpz_t bval; - if (!a->numeric_constant_value(&anc) - || !anc.to_int(&aval) - || !b->numeric_constant_value(&bnc) - || !bnc.to_int(&bval)) - go_unreachable(); - bool ret = mpz_cmp(aval, bval) == 0; - mpz_clear(aval); - mpz_clear(bval); - return ret; -} - -// Class Case_clauses::Case_clause. - -// Traversal. - -int -Case_clauses::Case_clause::traverse(Traverse* traverse) -{ - if (this->cases_ != NULL - && (traverse->traverse_mask() - & (Traverse::traverse_types | Traverse::traverse_expressions)) != 0) - { - if (this->cases_->traverse(traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - if (this->statements_ != NULL) - { - if (this->statements_->traverse(traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - return TRAVERSE_CONTINUE; -} - -// Check whether all the case expressions are integer constants. - -bool -Case_clauses::Case_clause::is_constant() const -{ - if (this->cases_ != NULL) - { - for (Expression_list::const_iterator p = this->cases_->begin(); - p != this->cases_->end(); - ++p) - if (!(*p)->is_constant() || (*p)->type()->integer_type() == NULL) - return false; - } - return true; -} - -// Lower a case clause for a nonconstant switch. VAL_TEMP is the -// value we are switching on; it may be NULL. If START_LABEL is not -// NULL, it goes at the start of the statements, after the condition -// test. We branch to FINISH_LABEL at the end of the statements. - -void -Case_clauses::Case_clause::lower(Block* b, Temporary_statement* val_temp, - Unnamed_label* start_label, - Unnamed_label* finish_label) const -{ - Location loc = this->location_; - Unnamed_label* next_case_label; - if (this->cases_ == NULL || this->cases_->empty()) - { - go_assert(this->is_default_); - next_case_label = NULL; - } - else - { - Expression* cond = NULL; - - for (Expression_list::const_iterator p = this->cases_->begin(); - p != this->cases_->end(); - ++p) - { - Expression* ref = Expression::make_temporary_reference(val_temp, - loc); - Expression* this_cond = Expression::make_binary(OPERATOR_EQEQ, ref, - *p, loc); - if (cond == NULL) - cond = this_cond; - else - cond = Expression::make_binary(OPERATOR_OROR, cond, this_cond, loc); - } - - Block* then_block = new Block(b, loc); - next_case_label = new Unnamed_label(Linemap::unknown_location()); - Statement* s = Statement::make_goto_unnamed_statement(next_case_label, - loc); - then_block->add_statement(s); - - // if !COND { goto NEXT_CASE_LABEL } - cond = Expression::make_unary(OPERATOR_NOT, cond, loc); - s = Statement::make_if_statement(cond, then_block, NULL, loc); - b->add_statement(s); - } - - if (start_label != NULL) - b->add_statement(Statement::make_unnamed_label_statement(start_label)); - - if (this->statements_ != NULL) - b->add_statement(Statement::make_block_statement(this->statements_, loc)); - - Statement* s = Statement::make_goto_unnamed_statement(finish_label, loc); - b->add_statement(s); - - if (next_case_label != NULL) - b->add_statement(Statement::make_unnamed_label_statement(next_case_label)); -} - -// Determine types. - -void -Case_clauses::Case_clause::determine_types(Type* type) -{ - if (this->cases_ != NULL) - { - Type_context case_context(type, false); - for (Expression_list::iterator p = this->cases_->begin(); - p != this->cases_->end(); - ++p) - (*p)->determine_type(&case_context); - } - if (this->statements_ != NULL) - this->statements_->determine_types(); -} - -// Check types. Returns false if there was an error. - -bool -Case_clauses::Case_clause::check_types(Type* type) -{ - if (this->cases_ != NULL) - { - for (Expression_list::iterator p = this->cases_->begin(); - p != this->cases_->end(); - ++p) - { - if (!Type::are_assignable(type, (*p)->type(), NULL) - && !Type::are_assignable((*p)->type(), type, NULL)) - { - error_at((*p)->location(), - "type mismatch between switch value and case clause"); - return false; - } - } - } - return true; -} - -// Return true if this clause may fall through to the following -// statements. Note that this is not the same as whether the case -// uses the "fallthrough" keyword. - -bool -Case_clauses::Case_clause::may_fall_through() const -{ - if (this->statements_ == NULL) - return true; - return this->statements_->may_fall_through(); -} - -// Convert the case values and statements to the backend -// representation. BREAK_LABEL is the label which break statements -// should branch to. CASE_CONSTANTS is used to detect duplicate -// constants. *CASES should be passed as an empty vector; the values -// for this case will be added to it. If this is the default case, -// *CASES will remain empty. This returns the statement to execute if -// one of these cases is selected. - -Bstatement* -Case_clauses::Case_clause::get_backend(Translate_context* context, - Unnamed_label* break_label, - Case_constants* case_constants, - std::vector<Bexpression*>* cases) const -{ - if (this->cases_ != NULL) - { - go_assert(!this->is_default_); - for (Expression_list::const_iterator p = this->cases_->begin(); - p != this->cases_->end(); - ++p) - { - Expression* e = *p; - if (e->classification() != Expression::EXPRESSION_INTEGER) - { - Numeric_constant nc; - mpz_t ival; - if (!(*p)->numeric_constant_value(&nc) || !nc.to_int(&ival)) - { - // Something went wrong. This can happen with a - // negative constant and an unsigned switch value. - go_assert(saw_errors()); - continue; - } - go_assert(nc.type() != NULL); - e = Expression::make_integer(&ival, nc.type(), e->location()); - mpz_clear(ival); - } - - std::pair<Case_constants::iterator, bool> ins = - case_constants->insert(e); - if (!ins.second) - { - // Value was already present. - error_at(this->location_, "duplicate case in switch"); - e = Expression::make_error(this->location_); - } - - tree case_tree = e->get_tree(context); - Bexpression* case_expr = tree_to_expr(case_tree); - cases->push_back(case_expr); - } - } - - Bstatement* statements; - if (this->statements_ == NULL) - statements = NULL; - else - { - Bblock* bblock = this->statements_->get_backend(context); - statements = context->backend()->block_statement(bblock); - } - - Bstatement* break_stat; - if (this->is_fallthrough_) - break_stat = NULL; - else - break_stat = break_label->get_goto(context, this->location_); - - if (statements == NULL) - return break_stat; - else if (break_stat == NULL) - return statements; - else - return context->backend()->compound_statement(statements, break_stat); -} - -// Dump the AST representation for a case clause - -void -Case_clauses::Case_clause::dump_clause(Ast_dump_context* ast_dump_context) - const -{ - ast_dump_context->print_indent(); - if (this->is_default_) - { - ast_dump_context->ostream() << "default:"; - } - else - { - ast_dump_context->ostream() << "case "; - ast_dump_context->dump_expression_list(this->cases_); - ast_dump_context->ostream() << ":" ; - } - ast_dump_context->dump_block(this->statements_); - if (this->is_fallthrough_) - { - ast_dump_context->print_indent(); - ast_dump_context->ostream() << " (fallthrough)" << std::endl; - } -} - -// Class Case_clauses. - -// Traversal. - -int -Case_clauses::traverse(Traverse* traverse) -{ - for (Clauses::iterator p = this->clauses_.begin(); - p != this->clauses_.end(); - ++p) - { - if (p->traverse(traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - return TRAVERSE_CONTINUE; -} - -// Check whether all the case expressions are constant. - -bool -Case_clauses::is_constant() const -{ - for (Clauses::const_iterator p = this->clauses_.begin(); - p != this->clauses_.end(); - ++p) - if (!p->is_constant()) - return false; - return true; -} - -// Lower case clauses for a nonconstant switch. - -void -Case_clauses::lower(Block* b, Temporary_statement* val_temp, - Unnamed_label* break_label) const -{ - // The default case. - const Case_clause* default_case = NULL; - - // The label for the fallthrough of the previous case. - Unnamed_label* last_fallthrough_label = NULL; - - // The label for the start of the default case. This is used if the - // case before the default case falls through. - Unnamed_label* default_start_label = NULL; - - // The label for the end of the default case. This normally winds - // up as BREAK_LABEL, but it will be different if the default case - // falls through. - Unnamed_label* default_finish_label = NULL; - - for (Clauses::const_iterator p = this->clauses_.begin(); - p != this->clauses_.end(); - ++p) - { - // The label to use for the start of the statements for this - // case. This is NULL unless the previous case falls through. - Unnamed_label* start_label = last_fallthrough_label; - - // The label to jump to after the end of the statements for this - // case. - Unnamed_label* finish_label = break_label; - - last_fallthrough_label = NULL; - if (p->is_fallthrough() && p + 1 != this->clauses_.end()) - { - finish_label = new Unnamed_label(p->location()); - last_fallthrough_label = finish_label; - } - - if (!p->is_default()) - p->lower(b, val_temp, start_label, finish_label); - else - { - // We have to move the default case to the end, so that we - // only use it if all the other tests fail. - default_case = &*p; - default_start_label = start_label; - default_finish_label = finish_label; - } - } - - if (default_case != NULL) - default_case->lower(b, val_temp, default_start_label, - default_finish_label); -} - -// Determine types. - -void -Case_clauses::determine_types(Type* type) -{ - for (Clauses::iterator p = this->clauses_.begin(); - p != this->clauses_.end(); - ++p) - p->determine_types(type); -} - -// Check types. Returns false if there was an error. - -bool -Case_clauses::check_types(Type* type) -{ - bool ret = true; - for (Clauses::iterator p = this->clauses_.begin(); - p != this->clauses_.end(); - ++p) - { - if (!p->check_types(type)) - ret = false; - } - return ret; -} - -// Return true if these clauses may fall through to the statements -// following the switch statement. - -bool -Case_clauses::may_fall_through() const -{ - bool found_default = false; - for (Clauses::const_iterator p = this->clauses_.begin(); - p != this->clauses_.end(); - ++p) - { - if (p->may_fall_through() && !p->is_fallthrough()) - return true; - if (p->is_default()) - found_default = true; - } - return !found_default; -} - -// Convert the cases to the backend representation. This sets -// *ALL_CASES and *ALL_STATEMENTS. - -void -Case_clauses::get_backend(Translate_context* context, - Unnamed_label* break_label, - std::vector<std::vector<Bexpression*> >* all_cases, - std::vector<Bstatement*>* all_statements) const -{ - Case_constants case_constants; - - size_t c = this->clauses_.size(); - all_cases->resize(c); - all_statements->resize(c); - - size_t i = 0; - for (Clauses::const_iterator p = this->clauses_.begin(); - p != this->clauses_.end(); - ++p, ++i) - { - std::vector<Bexpression*> cases; - Bstatement* stat = p->get_backend(context, break_label, &case_constants, - &cases); - (*all_cases)[i].swap(cases); - (*all_statements)[i] = stat; - } -} - -// Dump the AST representation for case clauses (from a switch statement) - -void -Case_clauses::dump_clauses(Ast_dump_context* ast_dump_context) const -{ - for (Clauses::const_iterator p = this->clauses_.begin(); - p != this->clauses_.end(); - ++p) - p->dump_clause(ast_dump_context); -} - -// A constant switch statement. A Switch_statement is lowered to this -// when all the cases are constants. - -class Constant_switch_statement : public Statement -{ - public: - Constant_switch_statement(Expression* val, Case_clauses* clauses, - Unnamed_label* break_label, - Location location) - : Statement(STATEMENT_CONSTANT_SWITCH, location), - val_(val), clauses_(clauses), break_label_(break_label) - { } - - protected: - int - do_traverse(Traverse*); - - void - do_determine_types(); - - void - do_check_types(Gogo*); - - bool - do_may_fall_through() const; - - Bstatement* - do_get_backend(Translate_context*); - - void - do_dump_statement(Ast_dump_context*) const; - - private: - // The value to switch on. - Expression* val_; - // The case clauses. - Case_clauses* clauses_; - // The break label, if needed. - Unnamed_label* break_label_; -}; - -// Traversal. - -int -Constant_switch_statement::do_traverse(Traverse* traverse) -{ - if (this->traverse_expression(traverse, &this->val_) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - return this->clauses_->traverse(traverse); -} - -// Determine types. - -void -Constant_switch_statement::do_determine_types() -{ - this->val_->determine_type_no_context(); - this->clauses_->determine_types(this->val_->type()); -} - -// Check types. - -void -Constant_switch_statement::do_check_types(Gogo*) -{ - if (!this->clauses_->check_types(this->val_->type())) - this->set_is_error(); -} - -// Return whether this switch may fall through. - -bool -Constant_switch_statement::do_may_fall_through() const -{ - if (this->clauses_ == NULL) - return true; - - // If we have a break label, then some case needed it. That implies - // that the switch statement as a whole can fall through. - if (this->break_label_ != NULL) - return true; - - return this->clauses_->may_fall_through(); -} - -// Convert to GENERIC. - -Bstatement* -Constant_switch_statement::do_get_backend(Translate_context* context) -{ - tree switch_val_tree = this->val_->get_tree(context); - Bexpression* switch_val_expr = tree_to_expr(switch_val_tree); - - Unnamed_label* break_label = this->break_label_; - if (break_label == NULL) - break_label = new Unnamed_label(this->location()); - - std::vector<std::vector<Bexpression*> > all_cases; - std::vector<Bstatement*> all_statements; - this->clauses_->get_backend(context, break_label, &all_cases, - &all_statements); - - Bstatement* switch_statement; - switch_statement = context->backend()->switch_statement(switch_val_expr, - all_cases, - all_statements, - this->location()); - Bstatement* ldef = break_label->get_definition(context); - return context->backend()->compound_statement(switch_statement, ldef); -} - -// Dump the AST representation for a constant switch statement. - -void -Constant_switch_statement::do_dump_statement(Ast_dump_context* ast_dump_context) - const -{ - ast_dump_context->print_indent(); - ast_dump_context->ostream() << "switch "; - ast_dump_context->dump_expression(this->val_); - - if (ast_dump_context->dump_subblocks()) - { - ast_dump_context->ostream() << " {" << std::endl; - this->clauses_->dump_clauses(ast_dump_context); - ast_dump_context->ostream() << "}"; - } - - ast_dump_context->ostream() << std::endl; -} - -// Class Switch_statement. - -// Traversal. - -int -Switch_statement::do_traverse(Traverse* traverse) -{ - if (this->val_ != NULL) - { - if (this->traverse_expression(traverse, &this->val_) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - return this->clauses_->traverse(traverse); -} - -// Lower a Switch_statement to a Constant_switch_statement or a series -// of if statements. - -Statement* -Switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing, - Statement_inserter*) -{ - Location loc = this->location(); - - if (this->val_ != NULL - && (this->val_->is_error_expression() - || this->val_->type()->is_error())) - return Statement::make_error_statement(loc); - - if (this->val_ != NULL - && this->val_->type()->integer_type() != NULL - && !this->clauses_->empty() - && this->clauses_->is_constant()) - return new Constant_switch_statement(this->val_, this->clauses_, - this->break_label_, loc); - - if (this->val_ != NULL - && !this->val_->type()->is_comparable() - && !Type::are_compatible_for_comparison(true, this->val_->type(), - Type::make_nil_type(), NULL)) - { - error_at(this->val_->location(), - "cannot switch on value whose type that may not be compared"); - return Statement::make_error_statement(loc); - } - - Block* b = new Block(enclosing, loc); - - if (this->clauses_->empty()) - { - Expression* val = this->val_; - if (val == NULL) - val = Expression::make_boolean(true, loc); - return Statement::make_statement(val, true); - } - - // var val_temp VAL_TYPE = VAL - Expression* val = this->val_; - if (val == NULL) - val = Expression::make_boolean(true, loc); - Temporary_statement* val_temp = Statement::make_temporary(NULL, val, loc); - b->add_statement(val_temp); - - this->clauses_->lower(b, val_temp, this->break_label()); - - Statement* s = Statement::make_unnamed_label_statement(this->break_label_); - b->add_statement(s); - - return Statement::make_block_statement(b, loc); -} - -// Return the break label for this switch statement, creating it if -// necessary. - -Unnamed_label* -Switch_statement::break_label() -{ - if (this->break_label_ == NULL) - this->break_label_ = new Unnamed_label(this->location()); - return this->break_label_; -} - -// Dump the AST representation for a switch statement. - -void -Switch_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const -{ - ast_dump_context->print_indent(); - ast_dump_context->ostream() << "switch "; - if (this->val_ != NULL) - { - ast_dump_context->dump_expression(this->val_); - } - if (ast_dump_context->dump_subblocks()) - { - ast_dump_context->ostream() << " {" << std::endl; - this->clauses_->dump_clauses(ast_dump_context); - ast_dump_context->print_indent(); - ast_dump_context->ostream() << "}"; - } - ast_dump_context->ostream() << std::endl; -} - -// Make a switch statement. - -Switch_statement* -Statement::make_switch_statement(Expression* val, Location location) -{ - return new Switch_statement(val, location); -} - -// Class Type_case_clauses::Type_case_clause. - -// Traversal. - -int -Type_case_clauses::Type_case_clause::traverse(Traverse* traverse) -{ - if (!this->is_default_ - && ((traverse->traverse_mask() - & (Traverse::traverse_types | Traverse::traverse_expressions)) != 0) - && Type::traverse(this->type_, traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - if (this->statements_ != NULL) - return this->statements_->traverse(traverse); - return TRAVERSE_CONTINUE; -} - -// Lower one clause in a type switch. Add statements to the block B. -// The type descriptor we are switching on is in DESCRIPTOR_TEMP. -// BREAK_LABEL is the label at the end of the type switch. -// *STMTS_LABEL, if not NULL, is a label to put at the start of the -// statements. - -void -Type_case_clauses::Type_case_clause::lower(Type* switch_val_type, - Block* b, - Temporary_statement* descriptor_temp, - Unnamed_label* break_label, - Unnamed_label** stmts_label) const -{ - Location loc = this->location_; - - Unnamed_label* next_case_label = NULL; - if (!this->is_default_) - { - Type* type = this->type_; - - std::string reason; - if (switch_val_type->interface_type() != NULL - && !type->is_nil_constant_as_type() - && type->interface_type() == NULL - && !switch_val_type->interface_type()->implements_interface(type, - &reason)) - { - if (reason.empty()) - error_at(this->location_, "impossible type switch case"); - else - error_at(this->location_, "impossible type switch case (%s)", - reason.c_str()); - } - - Expression* ref = Expression::make_temporary_reference(descriptor_temp, - loc); - - Expression* cond; - // The language permits case nil, which is of course a constant - // rather than a type. It will appear here as an invalid - // forwarding type. - if (type->is_nil_constant_as_type()) - cond = Expression::make_binary(OPERATOR_EQEQ, ref, - Expression::make_nil(loc), - loc); - else - cond = Runtime::make_call((type->interface_type() == NULL - ? Runtime::IFACETYPEEQ - : Runtime::IFACEI2TP), - loc, 2, - Expression::make_type_descriptor(type, loc), - ref); - - Unnamed_label* dest; - if (!this->is_fallthrough_) - { - // if !COND { goto NEXT_CASE_LABEL } - next_case_label = new Unnamed_label(Linemap::unknown_location()); - dest = next_case_label; - cond = Expression::make_unary(OPERATOR_NOT, cond, loc); - } - else - { - // if COND { goto STMTS_LABEL } - go_assert(stmts_label != NULL); - if (*stmts_label == NULL) - *stmts_label = new Unnamed_label(Linemap::unknown_location()); - dest = *stmts_label; - } - Block* then_block = new Block(b, loc); - Statement* s = Statement::make_goto_unnamed_statement(dest, loc); - then_block->add_statement(s); - s = Statement::make_if_statement(cond, then_block, NULL, loc); - b->add_statement(s); - } - - if (this->statements_ != NULL - || (!this->is_fallthrough_ - && stmts_label != NULL - && *stmts_label != NULL)) - { - go_assert(!this->is_fallthrough_); - if (stmts_label != NULL && *stmts_label != NULL) - { - go_assert(!this->is_default_); - if (this->statements_ != NULL) - (*stmts_label)->set_location(this->statements_->start_location()); - Statement* s = Statement::make_unnamed_label_statement(*stmts_label); - b->add_statement(s); - *stmts_label = NULL; - } - if (this->statements_ != NULL) - b->add_statement(Statement::make_block_statement(this->statements_, - loc)); - } - - if (this->is_fallthrough_) - go_assert(next_case_label == NULL); - else - { - Location gloc = (this->statements_ == NULL - ? loc - : this->statements_->end_location()); - b->add_statement(Statement::make_goto_unnamed_statement(break_label, - gloc)); - if (next_case_label != NULL) - { - Statement* s = - Statement::make_unnamed_label_statement(next_case_label); - b->add_statement(s); - } - } -} - -// Dump the AST representation for a type case clause - -void -Type_case_clauses::Type_case_clause::dump_clause( - Ast_dump_context* ast_dump_context) const -{ - ast_dump_context->print_indent(); - if (this->is_default_) - { - ast_dump_context->ostream() << "default:"; - } - else - { - ast_dump_context->ostream() << "case "; - ast_dump_context->dump_type(this->type_); - ast_dump_context->ostream() << ":" ; - } - ast_dump_context->dump_block(this->statements_); - if (this->is_fallthrough_) - { - ast_dump_context->print_indent(); - ast_dump_context->ostream() << " (fallthrough)" << std::endl; - } -} - -// Class Type_case_clauses. - -// Traversal. - -int -Type_case_clauses::traverse(Traverse* traverse) -{ - for (Type_clauses::iterator p = this->clauses_.begin(); - p != this->clauses_.end(); - ++p) - { - if (p->traverse(traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - return TRAVERSE_CONTINUE; -} - -// Check for duplicate types. - -void -Type_case_clauses::check_duplicates() const -{ - typedef Unordered_set_hash(const Type*, Type_hash_identical, - Type_identical) Types_seen; - Types_seen types_seen; - for (Type_clauses::const_iterator p = this->clauses_.begin(); - p != this->clauses_.end(); - ++p) - { - Type* t = p->type(); - if (t == NULL) - continue; - if (t->is_nil_constant_as_type()) - t = Type::make_nil_type(); - std::pair<Types_seen::iterator, bool> ins = types_seen.insert(t); - if (!ins.second) - error_at(p->location(), "duplicate type in switch"); - } -} - -// Lower the clauses in a type switch. Add statements to the block B. -// The type descriptor we are switching on is in DESCRIPTOR_TEMP. -// BREAK_LABEL is the label at the end of the type switch. - -void -Type_case_clauses::lower(Type* switch_val_type, Block* b, - Temporary_statement* descriptor_temp, - Unnamed_label* break_label) const -{ - const Type_case_clause* default_case = NULL; - - Unnamed_label* stmts_label = NULL; - for (Type_clauses::const_iterator p = this->clauses_.begin(); - p != this->clauses_.end(); - ++p) - { - if (!p->is_default()) - p->lower(switch_val_type, b, descriptor_temp, break_label, - &stmts_label); - else - { - // We are generating a series of tests, which means that we - // need to move the default case to the end. - default_case = &*p; - } - } - go_assert(stmts_label == NULL); - - if (default_case != NULL) - default_case->lower(switch_val_type, b, descriptor_temp, break_label, - NULL); -} - -// Dump the AST representation for case clauses (from a switch statement) - -void -Type_case_clauses::dump_clauses(Ast_dump_context* ast_dump_context) const -{ - for (Type_clauses::const_iterator p = this->clauses_.begin(); - p != this->clauses_.end(); - ++p) - p->dump_clause(ast_dump_context); -} - -// Class Type_switch_statement. - -// Traversal. - -int -Type_switch_statement::do_traverse(Traverse* traverse) -{ - if (this->var_ == NULL) - { - if (this->traverse_expression(traverse, &this->expr_) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - if (this->clauses_ != NULL) - return this->clauses_->traverse(traverse); - return TRAVERSE_CONTINUE; -} - -// Lower a type switch statement to a series of if statements. The gc -// compiler is able to generate a table in some cases. However, that -// does not work for us because we may have type descriptors in -// different shared libraries, so we can't compare them with simple -// equality testing. - -Statement* -Type_switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing, - Statement_inserter*) -{ - const Location loc = this->location(); - - if (this->clauses_ != NULL) - this->clauses_->check_duplicates(); - - Block* b = new Block(enclosing, loc); - - Type* val_type = (this->var_ != NULL - ? this->var_->var_value()->type() - : this->expr_->type()); - - if (val_type->interface_type() == NULL) - { - if (!val_type->is_error()) - this->report_error(_("cannot type switch on non-interface value")); - return Statement::make_error_statement(loc); - } - - // var descriptor_temp DESCRIPTOR_TYPE - Type* descriptor_type = Type::make_type_descriptor_ptr_type(); - Temporary_statement* descriptor_temp = - Statement::make_temporary(descriptor_type, NULL, loc); - b->add_statement(descriptor_temp); - - // descriptor_temp = ifacetype(val_temp) FIXME: This should be - // inlined. - bool is_empty = val_type->interface_type()->is_empty(); - Expression* ref; - if (this->var_ == NULL) - ref = this->expr_; - else - ref = Expression::make_var_reference(this->var_, loc); - Expression* call = Runtime::make_call((is_empty - ? Runtime::EFACETYPE - : Runtime::IFACETYPE), - loc, 1, ref); - Temporary_reference_expression* lhs = - Expression::make_temporary_reference(descriptor_temp, loc); - lhs->set_is_lvalue(); - Statement* s = Statement::make_assignment(lhs, call, loc); - b->add_statement(s); - - if (this->clauses_ != NULL) - this->clauses_->lower(val_type, b, descriptor_temp, this->break_label()); - - s = Statement::make_unnamed_label_statement(this->break_label_); - b->add_statement(s); - - return Statement::make_block_statement(b, loc); -} - -// Return the break label for this type switch statement, creating it -// if necessary. - -Unnamed_label* -Type_switch_statement::break_label() -{ - if (this->break_label_ == NULL) - this->break_label_ = new Unnamed_label(this->location()); - return this->break_label_; -} - -// Dump the AST representation for a type switch statement - -void -Type_switch_statement::do_dump_statement(Ast_dump_context* ast_dump_context) - const -{ - ast_dump_context->print_indent(); - ast_dump_context->ostream() << "switch " << this->var_->name() << " = "; - ast_dump_context->dump_expression(this->expr_); - ast_dump_context->ostream() << " .(type)"; - if (ast_dump_context->dump_subblocks()) - { - ast_dump_context->ostream() << " {" << std::endl; - this->clauses_->dump_clauses(ast_dump_context); - ast_dump_context->ostream() << "}"; - } - ast_dump_context->ostream() << std::endl; -} - -// Make a type switch statement. - -Type_switch_statement* -Statement::make_type_switch_statement(Named_object* var, Expression* expr, - Location location) -{ - return new Type_switch_statement(var, expr, location); -} - -// Class Send_statement. - -// Traversal. - -int -Send_statement::do_traverse(Traverse* traverse) -{ - if (this->traverse_expression(traverse, &this->channel_) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - return this->traverse_expression(traverse, &this->val_); -} - -// Determine types. - -void -Send_statement::do_determine_types() -{ - this->channel_->determine_type_no_context(); - Type* type = this->channel_->type(); - Type_context context; - if (type->channel_type() != NULL) - context.type = type->channel_type()->element_type(); - this->val_->determine_type(&context); -} - -// Check types. - -void -Send_statement::do_check_types(Gogo*) -{ - Type* type = this->channel_->type(); - if (type->is_error()) - { - this->set_is_error(); - return; - } - Channel_type* channel_type = type->channel_type(); - if (channel_type == NULL) - { - error_at(this->location(), "left operand of %<<-%> must be channel"); - this->set_is_error(); - return; - } - Type* element_type = channel_type->element_type(); - if (!Type::are_assignable(element_type, this->val_->type(), NULL)) - { - this->report_error(_("incompatible types in send")); - return; - } - if (!channel_type->may_send()) - { - this->report_error(_("invalid send on receive-only channel")); - return; - } -} - -// Convert a send statement to the backend representation. - -Bstatement* -Send_statement::do_get_backend(Translate_context* context) -{ - Location loc = this->location(); - - Channel_type* channel_type = this->channel_->type()->channel_type(); - Type* element_type = channel_type->element_type(); - Expression* val = Expression::make_cast(element_type, this->val_, loc); - - bool is_small; - bool can_take_address; - switch (element_type->base()->classification()) - { - case Type::TYPE_BOOLEAN: - case Type::TYPE_INTEGER: - case Type::TYPE_FUNCTION: - case Type::TYPE_POINTER: - case Type::TYPE_MAP: - case Type::TYPE_CHANNEL: - is_small = true; - can_take_address = false; - break; - - case Type::TYPE_FLOAT: - case Type::TYPE_COMPLEX: - case Type::TYPE_STRING: - case Type::TYPE_INTERFACE: - is_small = false; - can_take_address = false; - break; - - case Type::TYPE_STRUCT: - is_small = false; - can_take_address = true; - break; - - case Type::TYPE_ARRAY: - is_small = false; - can_take_address = !element_type->is_slice_type(); - break; - - default: - case Type::TYPE_ERROR: - case Type::TYPE_VOID: - case Type::TYPE_SINK: - case Type::TYPE_NIL: - case Type::TYPE_NAMED: - case Type::TYPE_FORWARD: - go_assert(saw_errors()); - return context->backend()->error_statement(); - } - - // Only try to take the address of a variable. We have already - // moved variables to the heap, so this should not cause that to - // happen unnecessarily. - if (can_take_address - && val->var_expression() == NULL - && val->temporary_reference_expression() == NULL) - can_take_address = false; - - Expression* td = Expression::make_type_descriptor(this->channel_->type(), - loc); - - Runtime::Function code; - Bstatement* btemp = NULL; - if (is_small) - { - // Type is small enough to handle as uint64. - code = Runtime::SEND_SMALL; - val = Expression::make_unsafe_cast(Type::lookup_integer_type("uint64"), - val, loc); - } - else if (can_take_address) - { - // Must pass address of value. The function doesn't change the - // value, so just take its address directly. - code = Runtime::SEND_BIG; - val = Expression::make_unary(OPERATOR_AND, val, loc); - } - else - { - // Must pass address of value, but the value is small enough - // that it might be in registers. Copy value into temporary - // variable to take address. - code = Runtime::SEND_BIG; - Temporary_statement* temp = Statement::make_temporary(element_type, - val, loc); - Expression* ref = Expression::make_temporary_reference(temp, loc); - val = Expression::make_unary(OPERATOR_AND, ref, loc); - btemp = temp->get_backend(context); - } - - Expression* call = Runtime::make_call(code, loc, 3, td, this->channel_, val); - - context->gogo()->lower_expression(context->function(), NULL, &call); - Bexpression* bcall = tree_to_expr(call->get_tree(context)); - Bstatement* s = context->backend()->expression_statement(bcall); - - if (btemp == NULL) - return s; - else - return context->backend()->compound_statement(btemp, s); -} - -// Dump the AST representation for a send statement - -void -Send_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const -{ - ast_dump_context->print_indent(); - ast_dump_context->dump_expression(this->channel_); - ast_dump_context->ostream() << " <- "; - ast_dump_context->dump_expression(this->val_); - ast_dump_context->ostream() << std::endl; -} - -// Make a send statement. - -Send_statement* -Statement::make_send_statement(Expression* channel, Expression* val, - Location location) -{ - return new Send_statement(channel, val, location); -} - -// Class Select_clauses::Select_clause. - -// Traversal. - -int -Select_clauses::Select_clause::traverse(Traverse* traverse) -{ - if (!this->is_lowered_ - && (traverse->traverse_mask() - & (Traverse::traverse_types | Traverse::traverse_expressions)) != 0) - { - if (this->channel_ != NULL) - { - if (Expression::traverse(&this->channel_, traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - if (this->val_ != NULL) - { - if (Expression::traverse(&this->val_, traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - if (this->closed_ != NULL) - { - if (Expression::traverse(&this->closed_, traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - } - if (this->statements_ != NULL) - { - if (this->statements_->traverse(traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - return TRAVERSE_CONTINUE; -} - -// Lowering. We call a function to register this clause, and arrange -// to set any variables in any receive clause. - -void -Select_clauses::Select_clause::lower(Gogo* gogo, Named_object* function, - Block* b, Temporary_statement* sel) -{ - Location loc = this->location_; - - Expression* selref = Expression::make_temporary_reference(sel, loc); - - mpz_t ival; - mpz_init_set_ui(ival, this->index_); - Expression* index_expr = Expression::make_integer(&ival, NULL, loc); - mpz_clear(ival); - - if (this->is_default_) - { - go_assert(this->channel_ == NULL && this->val_ == NULL); - this->lower_default(b, selref, index_expr); - this->is_lowered_ = true; - return; - } - - // Evaluate the channel before the select statement. - Temporary_statement* channel_temp = Statement::make_temporary(NULL, - this->channel_, - loc); - b->add_statement(channel_temp); - Expression* chanref = Expression::make_temporary_reference(channel_temp, - loc); - - if (this->is_send_) - this->lower_send(b, selref, chanref, index_expr); - else - this->lower_recv(gogo, function, b, selref, chanref, index_expr); - - // Now all references should be handled through the statements, not - // through here. - this->is_lowered_ = true; - this->val_ = NULL; - this->var_ = NULL; -} - -// Lower a default clause in a select statement. - -void -Select_clauses::Select_clause::lower_default(Block* b, Expression* selref, - Expression* index_expr) -{ - Location loc = this->location_; - Expression* call = Runtime::make_call(Runtime::SELECTDEFAULT, loc, 2, selref, - index_expr); - b->add_statement(Statement::make_statement(call, true)); -} - -// Lower a send clause in a select statement. - -void -Select_clauses::Select_clause::lower_send(Block* b, Expression* selref, - Expression* chanref, - Expression* index_expr) -{ - Location loc = this->location_; - - Channel_type* ct = this->channel_->type()->channel_type(); - if (ct == NULL) - return; - - Type* valtype = ct->element_type(); - - // Note that copying the value to a temporary here means that we - // evaluate the send values in the required order. - Temporary_statement* val = Statement::make_temporary(valtype, this->val_, - loc); - b->add_statement(val); - - Expression* valref = Expression::make_temporary_reference(val, loc); - Expression* valaddr = Expression::make_unary(OPERATOR_AND, valref, loc); - - Expression* call = Runtime::make_call(Runtime::SELECTSEND, loc, 4, selref, - chanref, valaddr, index_expr); - b->add_statement(Statement::make_statement(call, true)); -} - -// Lower a receive clause in a select statement. - -void -Select_clauses::Select_clause::lower_recv(Gogo* gogo, Named_object* function, - Block* b, Expression* selref, - Expression* chanref, - Expression* index_expr) -{ - Location loc = this->location_; - - Channel_type* ct = this->channel_->type()->channel_type(); - if (ct == NULL) - return; - - Type* valtype = ct->element_type(); - Temporary_statement* val = Statement::make_temporary(valtype, NULL, loc); - b->add_statement(val); - - Expression* valref = Expression::make_temporary_reference(val, loc); - Expression* valaddr = Expression::make_unary(OPERATOR_AND, valref, loc); - - Temporary_statement* closed_temp = NULL; - - Expression* call; - if (this->closed_ == NULL && this->closedvar_ == NULL) - call = Runtime::make_call(Runtime::SELECTRECV, loc, 4, selref, chanref, - valaddr, index_expr); - else - { - closed_temp = Statement::make_temporary(Type::lookup_bool_type(), NULL, - loc); - b->add_statement(closed_temp); - Expression* cref = Expression::make_temporary_reference(closed_temp, - loc); - Expression* caddr = Expression::make_unary(OPERATOR_AND, cref, loc); - call = Runtime::make_call(Runtime::SELECTRECV2, loc, 5, selref, chanref, - valaddr, caddr, index_expr); - } - - b->add_statement(Statement::make_statement(call, true)); - - // If the block of statements is executed, arrange for the received - // value to move from VAL to the place where the statements expect - // it. - - Block* init = NULL; - - if (this->var_ != NULL) - { - go_assert(this->val_ == NULL); - valref = Expression::make_temporary_reference(val, loc); - this->var_->var_value()->set_init(valref); - this->var_->var_value()->clear_type_from_chan_element(); - } - else if (this->val_ != NULL && !this->val_->is_sink_expression()) - { - init = new Block(b, loc); - valref = Expression::make_temporary_reference(val, loc); - init->add_statement(Statement::make_assignment(this->val_, valref, loc)); - } - - if (this->closedvar_ != NULL) - { - go_assert(this->closed_ == NULL); - Expression* cref = Expression::make_temporary_reference(closed_temp, - loc); - this->closedvar_->var_value()->set_init(cref); - } - else if (this->closed_ != NULL && !this->closed_->is_sink_expression()) - { - if (init == NULL) - init = new Block(b, loc); - Expression* cref = Expression::make_temporary_reference(closed_temp, - loc); - init->add_statement(Statement::make_assignment(this->closed_, cref, - loc)); - } - - if (init != NULL) - { - gogo->lower_block(function, init); - - if (this->statements_ != NULL) - init->add_statement(Statement::make_block_statement(this->statements_, - loc)); - this->statements_ = init; - } -} - -// Determine types. - -void -Select_clauses::Select_clause::determine_types() -{ - go_assert(this->is_lowered_); - if (this->statements_ != NULL) - this->statements_->determine_types(); -} - -// Check types. - -void -Select_clauses::Select_clause::check_types() -{ - if (this->is_default_) - return; - - Channel_type* ct = this->channel_->type()->channel_type(); - if (ct == NULL) - { - error_at(this->channel_->location(), "expected channel"); - return; - } - - if (this->is_send_ && !ct->may_send()) - error_at(this->location(), "invalid send on receive-only channel"); - else if (!this->is_send_ && !ct->may_receive()) - error_at(this->location(), "invalid receive on send-only channel"); -} - -// Whether this clause may fall through to the statement which follows -// the overall select statement. - -bool -Select_clauses::Select_clause::may_fall_through() const -{ - if (this->statements_ == NULL) - return true; - return this->statements_->may_fall_through(); -} - -// Return the backend representation for the statements to execute. - -Bstatement* -Select_clauses::Select_clause::get_statements_backend( - Translate_context* context) -{ - if (this->statements_ == NULL) - return NULL; - Bblock* bblock = this->statements_->get_backend(context); - return context->backend()->block_statement(bblock); -} - -// Dump the AST representation for a select case clause - -void -Select_clauses::Select_clause::dump_clause( - Ast_dump_context* ast_dump_context) const -{ - ast_dump_context->print_indent(); - if (this->is_default_) - { - ast_dump_context->ostream() << "default:"; - } - else - { - ast_dump_context->ostream() << "case " ; - if (this->is_send_) - { - ast_dump_context->dump_expression(this->channel_); - ast_dump_context->ostream() << " <- " ; - if (this->val_ != NULL) - ast_dump_context->dump_expression(this->val_); - } - else - { - if (this->val_ != NULL) - ast_dump_context->dump_expression(this->val_); - if (this->closed_ != NULL) - { - // FIXME: can val_ == NULL and closed_ ! = NULL? - ast_dump_context->ostream() << " , " ; - ast_dump_context->dump_expression(this->closed_); - } - if (this->closedvar_ != NULL || this->var_ != NULL) - ast_dump_context->ostream() << " := " ; - - ast_dump_context->ostream() << " <- " ; - ast_dump_context->dump_expression(this->channel_); - } - ast_dump_context->ostream() << ":" ; - } - ast_dump_context->dump_block(this->statements_); -} - -// Class Select_clauses. - -// Traversal. - -int -Select_clauses::traverse(Traverse* traverse) -{ - for (Clauses::iterator p = this->clauses_.begin(); - p != this->clauses_.end(); - ++p) - { - if (p->traverse(traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - return TRAVERSE_CONTINUE; -} - -// Lowering. Here we pull out the channel and the send values, to -// enforce the order of evaluation. We also add explicit send and -// receive statements to the clauses. - -void -Select_clauses::lower(Gogo* gogo, Named_object* function, Block* b, - Temporary_statement* sel) -{ - for (Clauses::iterator p = this->clauses_.begin(); - p != this->clauses_.end(); - ++p) - p->lower(gogo, function, b, sel); -} - -// Determine types. - -void -Select_clauses::determine_types() -{ - for (Clauses::iterator p = this->clauses_.begin(); - p != this->clauses_.end(); - ++p) - p->determine_types(); -} - -// Check types. - -void -Select_clauses::check_types() -{ - for (Clauses::iterator p = this->clauses_.begin(); - p != this->clauses_.end(); - ++p) - p->check_types(); -} - -// Return whether these select clauses fall through to the statement -// following the overall select statement. - -bool -Select_clauses::may_fall_through() const -{ - for (Clauses::const_iterator p = this->clauses_.begin(); - p != this->clauses_.end(); - ++p) - if (p->may_fall_through()) - return true; - return false; -} - -// Convert to the backend representation. We have already accumulated -// all the select information. Now we call selectgo, which will -// return the index of the clause to execute. - -Bstatement* -Select_clauses::get_backend(Translate_context* context, - Temporary_statement* sel, - Unnamed_label *break_label, - Location location) -{ - size_t count = this->clauses_.size(); - std::vector<std::vector<Bexpression*> > cases(count); - std::vector<Bstatement*> clauses(count); - - Type* int32_type = Type::lookup_integer_type("int32"); - - int i = 0; - for (Clauses::iterator p = this->clauses_.begin(); - p != this->clauses_.end(); - ++p, ++i) - { - int index = p->index(); - mpz_t ival; - mpz_init_set_ui(ival, index); - Expression* index_expr = Expression::make_integer(&ival, int32_type, - location); - mpz_clear(ival); - cases[i].push_back(tree_to_expr(index_expr->get_tree(context))); - - Bstatement* s = p->get_statements_backend(context); - Location gloc = (p->statements() == NULL - ? p->location() - : p->statements()->end_location()); - Bstatement* g = break_label->get_goto(context, gloc); - - if (s == NULL) - clauses[i] = g; - else - clauses[i] = context->backend()->compound_statement(s, g); - } - - Expression* selref = Expression::make_temporary_reference(sel, location); - Expression* call = Runtime::make_call(Runtime::SELECTGO, location, 1, - selref); - context->gogo()->lower_expression(context->function(), NULL, &call); - Bexpression* bcall = tree_to_expr(call->get_tree(context)); - - if (count == 0) - return context->backend()->expression_statement(bcall); - - std::vector<Bstatement*> statements; - statements.reserve(2); - - Bstatement* switch_stmt = context->backend()->switch_statement(bcall, - cases, - clauses, - location); - statements.push_back(switch_stmt); - - Bstatement* ldef = break_label->get_definition(context); - statements.push_back(ldef); - - return context->backend()->statement_list(statements); -} -// Dump the AST representation for select clauses. - -void -Select_clauses::dump_clauses(Ast_dump_context* ast_dump_context) const -{ - for (Clauses::const_iterator p = this->clauses_.begin(); - p != this->clauses_.end(); - ++p) - p->dump_clause(ast_dump_context); -} - -// Class Select_statement. - -// Return the break label for this switch statement, creating it if -// necessary. - -Unnamed_label* -Select_statement::break_label() -{ - if (this->break_label_ == NULL) - this->break_label_ = new Unnamed_label(this->location()); - return this->break_label_; -} - -// Lower a select statement. This will still return a select -// statement, but it will be modified to implement the order of -// evaluation rules, and to include the send and receive statements as -// explicit statements in the clauses. - -Statement* -Select_statement::do_lower(Gogo* gogo, Named_object* function, - Block* enclosing, Statement_inserter*) -{ - if (this->is_lowered_) - return this; - - Location loc = this->location(); - - Block* b = new Block(enclosing, loc); - - go_assert(this->sel_ == NULL); - - mpz_t ival; - mpz_init_set_ui(ival, this->clauses_->size()); - Expression* size_expr = Expression::make_integer(&ival, NULL, loc); - mpz_clear(ival); - - Expression* call = Runtime::make_call(Runtime::NEWSELECT, loc, 1, size_expr); - - this->sel_ = Statement::make_temporary(NULL, call, loc); - b->add_statement(this->sel_); - - this->clauses_->lower(gogo, function, b, this->sel_); - this->is_lowered_ = true; - b->add_statement(this); - - return Statement::make_block_statement(b, loc); -} - -// Return the backend representation for a select statement. - -Bstatement* -Select_statement::do_get_backend(Translate_context* context) -{ - return this->clauses_->get_backend(context, this->sel_, this->break_label(), - this->location()); -} - -// Dump the AST representation for a select statement. - -void -Select_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const -{ - ast_dump_context->print_indent(); - ast_dump_context->ostream() << "select"; - if (ast_dump_context->dump_subblocks()) - { - ast_dump_context->ostream() << " {" << std::endl; - this->clauses_->dump_clauses(ast_dump_context); - ast_dump_context->ostream() << "}"; - } - ast_dump_context->ostream() << std::endl; -} - -// Make a select statement. - -Select_statement* -Statement::make_select_statement(Location location) -{ - return new Select_statement(location); -} - -// Class For_statement. - -// Traversal. - -int -For_statement::do_traverse(Traverse* traverse) -{ - if (this->init_ != NULL) - { - if (this->init_->traverse(traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - if (this->cond_ != NULL) - { - if (this->traverse_expression(traverse, &this->cond_) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - if (this->post_ != NULL) - { - if (this->post_->traverse(traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - return this->statements_->traverse(traverse); -} - -// Lower a For_statement into if statements and gotos. Getting rid of -// complex statements make it easier to handle garbage collection. - -Statement* -For_statement::do_lower(Gogo*, Named_object*, Block* enclosing, - Statement_inserter*) -{ - Statement* s; - Location loc = this->location(); - - Block* b = new Block(enclosing, this->location()); - if (this->init_ != NULL) - { - s = Statement::make_block_statement(this->init_, - this->init_->start_location()); - b->add_statement(s); - } - - Unnamed_label* entry = NULL; - if (this->cond_ != NULL) - { - entry = new Unnamed_label(this->location()); - b->add_statement(Statement::make_goto_unnamed_statement(entry, loc)); - } - - Unnamed_label* top = new Unnamed_label(this->location()); - b->add_statement(Statement::make_unnamed_label_statement(top)); - - s = Statement::make_block_statement(this->statements_, - this->statements_->start_location()); - b->add_statement(s); - - Location end_loc = this->statements_->end_location(); - - Unnamed_label* cont = this->continue_label_; - if (cont != NULL) - b->add_statement(Statement::make_unnamed_label_statement(cont)); - - if (this->post_ != NULL) - { - s = Statement::make_block_statement(this->post_, - this->post_->start_location()); - b->add_statement(s); - end_loc = this->post_->end_location(); - } - - if (this->cond_ == NULL) - b->add_statement(Statement::make_goto_unnamed_statement(top, end_loc)); - else - { - b->add_statement(Statement::make_unnamed_label_statement(entry)); - - Location cond_loc = this->cond_->location(); - Block* then_block = new Block(b, cond_loc); - s = Statement::make_goto_unnamed_statement(top, cond_loc); - then_block->add_statement(s); - - s = Statement::make_if_statement(this->cond_, then_block, NULL, cond_loc); - b->add_statement(s); - } - - Unnamed_label* brk = this->break_label_; - if (brk != NULL) - b->add_statement(Statement::make_unnamed_label_statement(brk)); - - b->set_end_location(end_loc); - - return Statement::make_block_statement(b, loc); -} - -// Return the break label, creating it if necessary. - -Unnamed_label* -For_statement::break_label() -{ - if (this->break_label_ == NULL) - this->break_label_ = new Unnamed_label(this->location()); - return this->break_label_; -} - -// Return the continue LABEL_EXPR. - -Unnamed_label* -For_statement::continue_label() -{ - if (this->continue_label_ == NULL) - this->continue_label_ = new Unnamed_label(this->location()); - return this->continue_label_; -} - -// Set the break and continue labels a for statement. This is used -// when lowering a for range statement. - -void -For_statement::set_break_continue_labels(Unnamed_label* break_label, - Unnamed_label* continue_label) -{ - go_assert(this->break_label_ == NULL && this->continue_label_ == NULL); - this->break_label_ = break_label; - this->continue_label_ = continue_label; -} - -// Dump the AST representation for a for statement. - -void -For_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const -{ - if (this->init_ != NULL && ast_dump_context->dump_subblocks()) - { - ast_dump_context->print_indent(); - ast_dump_context->indent(); - ast_dump_context->ostream() << "// INIT " << std::endl; - ast_dump_context->dump_block(this->init_); - ast_dump_context->unindent(); - } - ast_dump_context->print_indent(); - ast_dump_context->ostream() << "for "; - if (this->cond_ != NULL) - ast_dump_context->dump_expression(this->cond_); - - if (ast_dump_context->dump_subblocks()) - { - ast_dump_context->ostream() << " {" << std::endl; - ast_dump_context->dump_block(this->statements_); - if (this->init_ != NULL) - { - ast_dump_context->print_indent(); - ast_dump_context->ostream() << "// POST " << std::endl; - ast_dump_context->dump_block(this->post_); - } - ast_dump_context->unindent(); - - ast_dump_context->print_indent(); - ast_dump_context->ostream() << "}"; - } - - ast_dump_context->ostream() << std::endl; -} - -// Make a for statement. - -For_statement* -Statement::make_for_statement(Block* init, Expression* cond, Block* post, - Location location) -{ - return new For_statement(init, cond, post, location); -} - -// Class For_range_statement. - -// Traversal. - -int -For_range_statement::do_traverse(Traverse* traverse) -{ - if (this->traverse_expression(traverse, &this->index_var_) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - if (this->value_var_ != NULL) - { - if (this->traverse_expression(traverse, &this->value_var_) - == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - if (this->traverse_expression(traverse, &this->range_) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - return this->statements_->traverse(traverse); -} - -// Lower a for range statement. For simplicity we lower this into a -// for statement, which will then be lowered in turn to goto -// statements. - -Statement* -For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing, - Statement_inserter*) -{ - Type* range_type = this->range_->type(); - if (range_type->points_to() != NULL - && range_type->points_to()->array_type() != NULL - && !range_type->points_to()->is_slice_type()) - range_type = range_type->points_to(); - - Type* index_type; - Type* value_type = NULL; - if (range_type->array_type() != NULL) - { - index_type = Type::lookup_integer_type("int"); - value_type = range_type->array_type()->element_type(); - } - else if (range_type->is_string_type()) - { - index_type = Type::lookup_integer_type("int"); - value_type = Type::lookup_integer_type("int32"); - } - else if (range_type->map_type() != NULL) - { - index_type = range_type->map_type()->key_type(); - value_type = range_type->map_type()->val_type(); - } - else if (range_type->channel_type() != NULL) - { - index_type = range_type->channel_type()->element_type(); - if (this->value_var_ != NULL) - { - if (!this->value_var_->type()->is_error()) - this->report_error(_("too many variables for range clause " - "with channel")); - return Statement::make_error_statement(this->location()); - } - } - else - { - this->report_error(_("range clause must have " - "array, slice, string, map, or channel type")); - return Statement::make_error_statement(this->location()); - } - - Location loc = this->location(); - Block* temp_block = new Block(enclosing, loc); - - Named_object* range_object = NULL; - Temporary_statement* range_temp = NULL; - Var_expression* ve = this->range_->var_expression(); - if (ve != NULL) - range_object = ve->named_object(); - else - { - range_temp = Statement::make_temporary(NULL, this->range_, loc); - temp_block->add_statement(range_temp); - this->range_ = NULL; - } - - Temporary_statement* index_temp = Statement::make_temporary(index_type, - NULL, loc); - temp_block->add_statement(index_temp); - - Temporary_statement* value_temp = NULL; - if (this->value_var_ != NULL) - { - value_temp = Statement::make_temporary(value_type, NULL, loc); - temp_block->add_statement(value_temp); - } - - Block* body = new Block(temp_block, loc); - - Block* init; - Expression* cond; - Block* iter_init; - Block* post; - - // Arrange to do a loop appropriate for the type. We will produce - // for INIT ; COND ; POST { - // ITER_INIT - // INDEX = INDEX_TEMP - // VALUE = VALUE_TEMP // If there is a value - // original statements - // } - - if (range_type->is_slice_type()) - this->lower_range_slice(gogo, temp_block, body, range_object, range_temp, - index_temp, value_temp, &init, &cond, &iter_init, - &post); - else if (range_type->array_type() != NULL) - this->lower_range_array(gogo, temp_block, body, range_object, range_temp, - index_temp, value_temp, &init, &cond, &iter_init, - &post); - else if (range_type->is_string_type()) - this->lower_range_string(gogo, temp_block, body, range_object, range_temp, - index_temp, value_temp, &init, &cond, &iter_init, - &post); - else if (range_type->map_type() != NULL) - this->lower_range_map(gogo, temp_block, body, range_object, range_temp, - index_temp, value_temp, &init, &cond, &iter_init, - &post); - else if (range_type->channel_type() != NULL) - this->lower_range_channel(gogo, temp_block, body, range_object, range_temp, - index_temp, value_temp, &init, &cond, &iter_init, - &post); - else - go_unreachable(); - - if (iter_init != NULL) - body->add_statement(Statement::make_block_statement(iter_init, loc)); - - Statement* assign; - Expression* index_ref = Expression::make_temporary_reference(index_temp, loc); - if (this->value_var_ == NULL) - { - assign = Statement::make_assignment(this->index_var_, index_ref, loc); - } - else - { - Expression_list* lhs = new Expression_list(); - lhs->push_back(this->index_var_); - lhs->push_back(this->value_var_); - - Expression_list* rhs = new Expression_list(); - rhs->push_back(index_ref); - rhs->push_back(Expression::make_temporary_reference(value_temp, loc)); - - assign = Statement::make_tuple_assignment(lhs, rhs, loc); - } - body->add_statement(assign); - - body->add_statement(Statement::make_block_statement(this->statements_, loc)); - - body->set_end_location(this->statements_->end_location()); - - For_statement* loop = Statement::make_for_statement(init, cond, post, - this->location()); - loop->add_statements(body); - loop->set_break_continue_labels(this->break_label_, this->continue_label_); - - temp_block->add_statement(loop); - - return Statement::make_block_statement(temp_block, loc); -} - -// Return a reference to the range, which may be in RANGE_OBJECT or in -// RANGE_TEMP. - -Expression* -For_range_statement::make_range_ref(Named_object* range_object, - Temporary_statement* range_temp, - Location loc) -{ - if (range_object != NULL) - return Expression::make_var_reference(range_object, loc); - else - return Expression::make_temporary_reference(range_temp, loc); -} - -// Return a call to the predeclared function FUNCNAME passing a -// reference to the temporary variable ARG. - -Expression* -For_range_statement::call_builtin(Gogo* gogo, const char* funcname, - Expression* arg, - Location loc) -{ - Named_object* no = gogo->lookup_global(funcname); - go_assert(no != NULL && no->is_function_declaration()); - Expression* func = Expression::make_func_reference(no, NULL, loc); - Expression_list* params = new Expression_list(); - params->push_back(arg); - return Expression::make_call(func, params, false, loc); -} - -// Lower a for range over an array. - -void -For_range_statement::lower_range_array(Gogo* gogo, - Block* enclosing, - Block* body_block, - Named_object* range_object, - Temporary_statement* range_temp, - Temporary_statement* index_temp, - Temporary_statement* value_temp, - Block** pinit, - Expression** pcond, - Block** piter_init, - Block** ppost) -{ - Location loc = this->location(); - - // The loop we generate: - // len_temp := len(range) - // for index_temp = 0; index_temp < len_temp; index_temp++ { - // value_temp = range[index_temp] - // index = index_temp - // value = value_temp - // original body - // } - - // Set *PINIT to - // var len_temp int - // len_temp = len(range) - // index_temp = 0 - - Block* init = new Block(enclosing, loc); - - Expression* ref = this->make_range_ref(range_object, range_temp, loc); - Expression* len_call = this->call_builtin(gogo, "len", ref, loc); - Temporary_statement* len_temp = Statement::make_temporary(index_temp->type(), - len_call, loc); - init->add_statement(len_temp); - - mpz_t zval; - mpz_init_set_ui(zval, 0UL); - Expression* zexpr = Expression::make_integer(&zval, NULL, loc); - mpz_clear(zval); - - Temporary_reference_expression* tref = - Expression::make_temporary_reference(index_temp, loc); - tref->set_is_lvalue(); - Statement* s = Statement::make_assignment(tref, zexpr, loc); - init->add_statement(s); - - *pinit = init; - - // Set *PCOND to - // index_temp < len_temp - - ref = Expression::make_temporary_reference(index_temp, loc); - Expression* ref2 = Expression::make_temporary_reference(len_temp, loc); - Expression* lt = Expression::make_binary(OPERATOR_LT, ref, ref2, loc); - - *pcond = lt; - - // Set *PITER_INIT to - // value_temp = range[index_temp] - - Block* iter_init = NULL; - if (value_temp != NULL) - { - iter_init = new Block(body_block, loc); - - ref = this->make_range_ref(range_object, range_temp, loc); - Expression* ref2 = Expression::make_temporary_reference(index_temp, loc); - Expression* index = Expression::make_index(ref, ref2, NULL, loc); - - tref = Expression::make_temporary_reference(value_temp, loc); - tref->set_is_lvalue(); - s = Statement::make_assignment(tref, index, loc); - - iter_init->add_statement(s); - } - *piter_init = iter_init; - - // Set *PPOST to - // index_temp++ - - Block* post = new Block(enclosing, loc); - tref = Expression::make_temporary_reference(index_temp, loc); - tref->set_is_lvalue(); - s = Statement::make_inc_statement(tref); - post->add_statement(s); - *ppost = post; -} - -// Lower a for range over a slice. - -void -For_range_statement::lower_range_slice(Gogo* gogo, - Block* enclosing, - Block* body_block, - Named_object* range_object, - Temporary_statement* range_temp, - Temporary_statement* index_temp, - Temporary_statement* value_temp, - Block** pinit, - Expression** pcond, - Block** piter_init, - Block** ppost) -{ - Location loc = this->location(); - - // The loop we generate: - // for_temp := range - // len_temp := len(for_temp) - // for index_temp = 0; index_temp < len_temp; index_temp++ { - // value_temp = for_temp[index_temp] - // index = index_temp - // value = value_temp - // original body - // } - // - // Using for_temp means that we don't need to check bounds when - // fetching range_temp[index_temp]. - - // Set *PINIT to - // range_temp := range - // var len_temp int - // len_temp = len(range_temp) - // index_temp = 0 - - Block* init = new Block(enclosing, loc); - - Expression* ref = this->make_range_ref(range_object, range_temp, loc); - Temporary_statement* for_temp = Statement::make_temporary(NULL, ref, loc); - init->add_statement(for_temp); - - ref = Expression::make_temporary_reference(for_temp, loc); - Expression* len_call = this->call_builtin(gogo, "len", ref, loc); - Temporary_statement* len_temp = Statement::make_temporary(index_temp->type(), - len_call, loc); - init->add_statement(len_temp); - - mpz_t zval; - mpz_init_set_ui(zval, 0UL); - Expression* zexpr = Expression::make_integer(&zval, NULL, loc); - mpz_clear(zval); - - Temporary_reference_expression* tref = - Expression::make_temporary_reference(index_temp, loc); - tref->set_is_lvalue(); - Statement* s = Statement::make_assignment(tref, zexpr, loc); - init->add_statement(s); - - *pinit = init; - - // Set *PCOND to - // index_temp < len_temp - - ref = Expression::make_temporary_reference(index_temp, loc); - Expression* ref2 = Expression::make_temporary_reference(len_temp, loc); - Expression* lt = Expression::make_binary(OPERATOR_LT, ref, ref2, loc); - - *pcond = lt; - - // Set *PITER_INIT to - // value_temp = range[index_temp] - - Block* iter_init = NULL; - if (value_temp != NULL) - { - iter_init = new Block(body_block, loc); - - ref = Expression::make_temporary_reference(for_temp, loc); - Expression* ref2 = Expression::make_temporary_reference(index_temp, loc); - Expression* index = Expression::make_index(ref, ref2, NULL, loc); - - tref = Expression::make_temporary_reference(value_temp, loc); - tref->set_is_lvalue(); - s = Statement::make_assignment(tref, index, loc); - - iter_init->add_statement(s); - } - *piter_init = iter_init; - - // Set *PPOST to - // index_temp++ - - Block* post = new Block(enclosing, loc); - tref = Expression::make_temporary_reference(index_temp, loc); - tref->set_is_lvalue(); - s = Statement::make_inc_statement(tref); - post->add_statement(s); - *ppost = post; -} - -// Lower a for range over a string. - -void -For_range_statement::lower_range_string(Gogo*, - Block* enclosing, - Block* body_block, - Named_object* range_object, - Temporary_statement* range_temp, - Temporary_statement* index_temp, - Temporary_statement* value_temp, - Block** pinit, - Expression** pcond, - Block** piter_init, - Block** ppost) -{ - Location loc = this->location(); - - // The loop we generate: - // var next_index_temp int - // for index_temp = 0; ; index_temp = next_index_temp { - // next_index_temp, value_temp = stringiter2(range, index_temp) - // if next_index_temp == 0 { - // break - // } - // index = index_temp - // value = value_temp - // original body - // } - - // Set *PINIT to - // var next_index_temp int - // index_temp = 0 - - Block* init = new Block(enclosing, loc); - - Temporary_statement* next_index_temp = - Statement::make_temporary(index_temp->type(), NULL, loc); - init->add_statement(next_index_temp); - - mpz_t zval; - mpz_init_set_ui(zval, 0UL); - Expression* zexpr = Expression::make_integer(&zval, NULL, loc); - - Temporary_reference_expression* ref = - Expression::make_temporary_reference(index_temp, loc); - ref->set_is_lvalue(); - Statement* s = Statement::make_assignment(ref, zexpr, loc); - - init->add_statement(s); - *pinit = init; - - // The loop has no condition. - - *pcond = NULL; - - // Set *PITER_INIT to - // next_index_temp = runtime.stringiter(range, index_temp) - // or - // next_index_temp, value_temp = runtime.stringiter2(range, index_temp) - // followed by - // if next_index_temp == 0 { - // break - // } - - Block* iter_init = new Block(body_block, loc); - - Expression* p1 = this->make_range_ref(range_object, range_temp, loc); - Expression* p2 = Expression::make_temporary_reference(index_temp, loc); - Call_expression* call = Runtime::make_call((value_temp == NULL - ? Runtime::STRINGITER - : Runtime::STRINGITER2), - loc, 2, p1, p2); - - if (value_temp == NULL) - { - ref = Expression::make_temporary_reference(next_index_temp, loc); - ref->set_is_lvalue(); - s = Statement::make_assignment(ref, call, loc); - } - else - { - Expression_list* lhs = new Expression_list(); - - ref = Expression::make_temporary_reference(next_index_temp, loc); - ref->set_is_lvalue(); - lhs->push_back(ref); - - ref = Expression::make_temporary_reference(value_temp, loc); - ref->set_is_lvalue(); - lhs->push_back(ref); - - Expression_list* rhs = new Expression_list(); - rhs->push_back(Expression::make_call_result(call, 0)); - rhs->push_back(Expression::make_call_result(call, 1)); - - s = Statement::make_tuple_assignment(lhs, rhs, loc); - } - iter_init->add_statement(s); - - ref = Expression::make_temporary_reference(next_index_temp, loc); - zexpr = Expression::make_integer(&zval, NULL, loc); - mpz_clear(zval); - Expression* equals = Expression::make_binary(OPERATOR_EQEQ, ref, zexpr, loc); - - Block* then_block = new Block(iter_init, loc); - s = Statement::make_break_statement(this->break_label(), loc); - then_block->add_statement(s); - - s = Statement::make_if_statement(equals, then_block, NULL, loc); - iter_init->add_statement(s); - - *piter_init = iter_init; - - // Set *PPOST to - // index_temp = next_index_temp - - Block* post = new Block(enclosing, loc); - - Temporary_reference_expression* lhs = - Expression::make_temporary_reference(index_temp, loc); - lhs->set_is_lvalue(); - Expression* rhs = Expression::make_temporary_reference(next_index_temp, loc); - s = Statement::make_assignment(lhs, rhs, loc); - - post->add_statement(s); - *ppost = post; -} - -// Lower a for range over a map. - -void -For_range_statement::lower_range_map(Gogo*, - Block* enclosing, - Block* body_block, - Named_object* range_object, - Temporary_statement* range_temp, - Temporary_statement* index_temp, - Temporary_statement* value_temp, - Block** pinit, - Expression** pcond, - Block** piter_init, - Block** ppost) -{ - Location loc = this->location(); - - // The runtime uses a struct to handle ranges over a map. The - // struct is four pointers long. The first pointer is NULL when we - // have completed the iteration. - - // The loop we generate: - // var hiter map_iteration_struct - // for mapiterinit(range, &hiter); hiter[0] != nil; mapiternext(&hiter) { - // mapiter2(hiter, &index_temp, &value_temp) - // index = index_temp - // value = value_temp - // original body - // } - - // Set *PINIT to - // var hiter map_iteration_struct - // runtime.mapiterinit(range, &hiter) - - Block* init = new Block(enclosing, loc); - - Type* map_iteration_type = Runtime::map_iteration_type(); - Temporary_statement* hiter = Statement::make_temporary(map_iteration_type, - NULL, loc); - init->add_statement(hiter); - - Expression* p1 = this->make_range_ref(range_object, range_temp, loc); - Expression* ref = Expression::make_temporary_reference(hiter, loc); - Expression* p2 = Expression::make_unary(OPERATOR_AND, ref, loc); - Expression* call = Runtime::make_call(Runtime::MAPITERINIT, loc, 2, p1, p2); - init->add_statement(Statement::make_statement(call, true)); - - *pinit = init; - - // Set *PCOND to - // hiter[0] != nil - - ref = Expression::make_temporary_reference(hiter, loc); - - mpz_t zval; - mpz_init_set_ui(zval, 0UL); - Expression* zexpr = Expression::make_integer(&zval, NULL, loc); - mpz_clear(zval); - - Expression* index = Expression::make_index(ref, zexpr, NULL, loc); - - Expression* ne = Expression::make_binary(OPERATOR_NOTEQ, index, - Expression::make_nil(loc), - loc); - - *pcond = ne; - - // Set *PITER_INIT to - // mapiter1(hiter, &index_temp) - // or - // mapiter2(hiter, &index_temp, &value_temp) - - Block* iter_init = new Block(body_block, loc); - - ref = Expression::make_temporary_reference(hiter, loc); - p1 = Expression::make_unary(OPERATOR_AND, ref, loc); - ref = Expression::make_temporary_reference(index_temp, loc); - p2 = Expression::make_unary(OPERATOR_AND, ref, loc); - if (value_temp == NULL) - call = Runtime::make_call(Runtime::MAPITER1, loc, 2, p1, p2); - else - { - ref = Expression::make_temporary_reference(value_temp, loc); - Expression* p3 = Expression::make_unary(OPERATOR_AND, ref, loc); - call = Runtime::make_call(Runtime::MAPITER2, loc, 3, p1, p2, p3); - } - iter_init->add_statement(Statement::make_statement(call, true)); - - *piter_init = iter_init; - - // Set *PPOST to - // mapiternext(&hiter) - - Block* post = new Block(enclosing, loc); - - ref = Expression::make_temporary_reference(hiter, loc); - p1 = Expression::make_unary(OPERATOR_AND, ref, loc); - call = Runtime::make_call(Runtime::MAPITERNEXT, loc, 1, p1); - post->add_statement(Statement::make_statement(call, true)); - - *ppost = post; -} - -// Lower a for range over a channel. - -void -For_range_statement::lower_range_channel(Gogo*, - Block*, - Block* body_block, - Named_object* range_object, - Temporary_statement* range_temp, - Temporary_statement* index_temp, - Temporary_statement* value_temp, - Block** pinit, - Expression** pcond, - Block** piter_init, - Block** ppost) -{ - go_assert(value_temp == NULL); - - Location loc = this->location(); - - // The loop we generate: - // for { - // index_temp, ok_temp = <-range - // if !ok_temp { - // break - // } - // index = index_temp - // original body - // } - - // We have no initialization code, no condition, and no post code. - - *pinit = NULL; - *pcond = NULL; - *ppost = NULL; - - // Set *PITER_INIT to - // index_temp, ok_temp = <-range - // if !ok_temp { - // break - // } - - Block* iter_init = new Block(body_block, loc); - - Temporary_statement* ok_temp = - Statement::make_temporary(Type::lookup_bool_type(), NULL, loc); - iter_init->add_statement(ok_temp); - - Expression* cref = this->make_range_ref(range_object, range_temp, loc); - Temporary_reference_expression* iref = - Expression::make_temporary_reference(index_temp, loc); - iref->set_is_lvalue(); - Temporary_reference_expression* oref = - Expression::make_temporary_reference(ok_temp, loc); - oref->set_is_lvalue(); - Statement* s = Statement::make_tuple_receive_assignment(iref, oref, cref, - loc); - iter_init->add_statement(s); - - Block* then_block = new Block(iter_init, loc); - s = Statement::make_break_statement(this->break_label(), loc); - then_block->add_statement(s); - - oref = Expression::make_temporary_reference(ok_temp, loc); - Expression* cond = Expression::make_unary(OPERATOR_NOT, oref, loc); - s = Statement::make_if_statement(cond, then_block, NULL, loc); - iter_init->add_statement(s); - - *piter_init = iter_init; -} - -// Return the break LABEL_EXPR. - -Unnamed_label* -For_range_statement::break_label() -{ - if (this->break_label_ == NULL) - this->break_label_ = new Unnamed_label(this->location()); - return this->break_label_; -} - -// Return the continue LABEL_EXPR. - -Unnamed_label* -For_range_statement::continue_label() -{ - if (this->continue_label_ == NULL) - this->continue_label_ = new Unnamed_label(this->location()); - return this->continue_label_; -} - -// Dump the AST representation for a for range statement. - -void -For_range_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const -{ - - ast_dump_context->print_indent(); - ast_dump_context->ostream() << "for "; - ast_dump_context->dump_expression(this->index_var_); - if (this->value_var_ != NULL) - { - ast_dump_context->ostream() << ", "; - ast_dump_context->dump_expression(this->value_var_); - } - - ast_dump_context->ostream() << " = range "; - ast_dump_context->dump_expression(this->range_); - if (ast_dump_context->dump_subblocks()) - { - ast_dump_context->ostream() << " {" << std::endl; - - ast_dump_context->indent(); - - ast_dump_context->dump_block(this->statements_); - - ast_dump_context->unindent(); - ast_dump_context->print_indent(); - ast_dump_context->ostream() << "}"; - } - ast_dump_context->ostream() << std::endl; -} - -// Make a for statement with a range clause. - -For_range_statement* -Statement::make_for_range_statement(Expression* index_var, - Expression* value_var, - Expression* range, - Location location) -{ - return new For_range_statement(index_var, value_var, range, location); -} diff --git a/gcc-4.8.1/gcc/go/gofrontend/statements.h b/gcc-4.8.1/gcc/go/gofrontend/statements.h deleted file mode 100644 index c59957107..000000000 --- a/gcc-4.8.1/gcc/go/gofrontend/statements.h +++ /dev/null @@ -1,1570 +0,0 @@ -// statements.h -- Go frontend statements. -*- C++ -*- - -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#ifndef GO_STATEMENTS_H -#define GO_STATEMENTS_H - -#include "operator.h" - -class Gogo; -class Traverse; -class Statement_inserter; -class Block; -class Function; -class Unnamed_label; -class Temporary_statement; -class Variable_declaration_statement; -class Return_statement; -class Thunk_statement; -class Label_statement; -class For_statement; -class For_range_statement; -class Switch_statement; -class Type_switch_statement; -class Send_statement; -class Select_statement; -class Variable; -class Named_object; -class Label; -class Translate_context; -class Expression; -class Expression_list; -class Struct_type; -class Call_expression; -class Map_index_expression; -class Receive_expression; -class Case_clauses; -class Type_case_clauses; -class Select_clauses; -class Typed_identifier_list; -class Bexpression; -class Bstatement; -class Bvariable; -class Ast_dump_context; - -// This class is used to traverse assignments made by a statement -// which makes assignments. - -class Traverse_assignments -{ - public: - Traverse_assignments() - { } - - virtual ~Traverse_assignments() - { } - - // This is called for a variable initialization. - virtual void - initialize_variable(Named_object*) = 0; - - // This is called for each assignment made by the statement. PLHS - // points to the left hand side, and PRHS points to the right hand - // side. PRHS may be NULL if there is no associated expression, as - // in the bool set by a non-blocking receive. - virtual void - assignment(Expression** plhs, Expression** prhs) = 0; - - // This is called for each expression which is not passed to the - // assignment function. This is used for some of the statements - // which assign two values, for which there is no expression which - // describes the value. For ++ and -- the value is passed to both - // the assignment method and the rhs method. IS_STORED is true if - // this value is being stored directly. It is false if the value is - // computed but not stored. IS_LOCAL is true if the value is being - // stored in a local variable or this is being called by a return - // statement. - virtual void - value(Expression**, bool is_stored, bool is_local) = 0; -}; - -// A single statement. - -class Statement -{ - public: - // The types of statements. - enum Statement_classification - { - STATEMENT_ERROR, - STATEMENT_VARIABLE_DECLARATION, - STATEMENT_TEMPORARY, - STATEMENT_ASSIGNMENT, - STATEMENT_EXPRESSION, - STATEMENT_BLOCK, - STATEMENT_GO, - STATEMENT_DEFER, - STATEMENT_RETURN, - STATEMENT_BREAK_OR_CONTINUE, - STATEMENT_GOTO, - STATEMENT_GOTO_UNNAMED, - STATEMENT_LABEL, - STATEMENT_UNNAMED_LABEL, - STATEMENT_IF, - STATEMENT_CONSTANT_SWITCH, - STATEMENT_SEND, - STATEMENT_SELECT, - - // These statements types are created by the parser, but they - // disappear during the lowering pass. - STATEMENT_ASSIGNMENT_OPERATION, - STATEMENT_TUPLE_ASSIGNMENT, - STATEMENT_TUPLE_MAP_ASSIGNMENT, - STATEMENT_MAP_ASSIGNMENT, - STATEMENT_TUPLE_RECEIVE_ASSIGNMENT, - STATEMENT_TUPLE_TYPE_GUARD_ASSIGNMENT, - STATEMENT_INCDEC, - STATEMENT_FOR, - STATEMENT_FOR_RANGE, - STATEMENT_SWITCH, - STATEMENT_TYPE_SWITCH - }; - - Statement(Statement_classification, Location); - - virtual ~Statement(); - - // Make a variable declaration. - static Statement* - make_variable_declaration(Named_object*); - - // Make a statement which creates a temporary variable and - // initializes it to an expression. The block is used if the - // temporary variable has to be explicitly destroyed; the variable - // must still be added to the block. References to the temporary - // variable may be constructed using make_temporary_reference. - // Either the type or the initialization expression may be NULL, but - // not both. - static Temporary_statement* - make_temporary(Type*, Expression*, Location); - - // Make an assignment statement. - static Statement* - make_assignment(Expression*, Expression*, Location); - - // Make an assignment operation (+=, etc.). - static Statement* - make_assignment_operation(Operator, Expression*, Expression*, - Location); - - // Make a tuple assignment statement. - static Statement* - make_tuple_assignment(Expression_list*, Expression_list*, Location); - - // Make an assignment from a map index to a pair of variables. - static Statement* - make_tuple_map_assignment(Expression* val, Expression* present, - Expression*, Location); - - // Make a statement which assigns a pair of values to a map. - static Statement* - make_map_assignment(Expression*, Expression* val, - Expression* should_set, Location); - - // Make an assignment from a nonblocking receive to a pair of - // variables. - static Statement* - make_tuple_receive_assignment(Expression* val, Expression* closed, - Expression* channel, Location); - - // Make an assignment from a type guard to a pair of variables. - static Statement* - make_tuple_type_guard_assignment(Expression* val, Expression* ok, - Expression* expr, Type* type, - Location); - - // Make an expression statement from an Expression. IS_IGNORED is - // true if the value is being explicitly ignored, as in an - // assignment to _. - static Statement* - make_statement(Expression*, bool is_ignored); - - // Make a block statement from a Block. This is an embedded list of - // statements which may also include variable definitions. - static Statement* - make_block_statement(Block*, Location); - - // Make an increment statement. - static Statement* - make_inc_statement(Expression*); - - // Make a decrement statement. - static Statement* - make_dec_statement(Expression*); - - // Make a go statement. - static Statement* - make_go_statement(Call_expression* call, Location); - - // Make a defer statement. - static Statement* - make_defer_statement(Call_expression* call, Location); - - // Make a return statement. - static Return_statement* - make_return_statement(Expression_list*, Location); - - // Make a break statement. - static Statement* - make_break_statement(Unnamed_label* label, Location); - - // Make a continue statement. - static Statement* - make_continue_statement(Unnamed_label* label, Location); - - // Make a goto statement. - static Statement* - make_goto_statement(Label* label, Location); - - // Make a goto statement to an unnamed label. - static Statement* - make_goto_unnamed_statement(Unnamed_label* label, Location); - - // Make a label statement--where the label is defined. - static Statement* - make_label_statement(Label* label, Location); - - // Make an unnamed label statement--where the label is defined. - static Statement* - make_unnamed_label_statement(Unnamed_label* label); - - // Make an if statement. - static Statement* - make_if_statement(Expression* cond, Block* then_block, Block* else_block, - Location); - - // Make a switch statement. - static Switch_statement* - make_switch_statement(Expression* switch_val, Location); - - // Make a type switch statement. - static Type_switch_statement* - make_type_switch_statement(Named_object* var, Expression*, Location); - - // Make a send statement. - static Send_statement* - make_send_statement(Expression* channel, Expression* val, Location); - - // Make a select statement. - static Select_statement* - make_select_statement(Location); - - // Make a for statement. - static For_statement* - make_for_statement(Block* init, Expression* cond, Block* post, - Location location); - - // Make a for statement with a range clause. - static For_range_statement* - make_for_range_statement(Expression* index_var, Expression* value_var, - Expression* range, Location); - - // Return the statement classification. - Statement_classification - classification() const - { return this->classification_; } - - // Get the statement location. - Location - location() const - { return this->location_; } - - // Traverse the tree. - int - traverse(Block*, size_t* index, Traverse*); - - // Traverse the contents of this statement--the expressions and - // statements which it contains. - int - traverse_contents(Traverse*); - - // If this statement assigns some values, it calls a function for - // each value to which this statement assigns a value, and returns - // true. If this statement does not assign any values, it returns - // false. - bool - traverse_assignments(Traverse_assignments* tassign); - - // Lower a statement. This is called immediately after parsing to - // simplify statements for further processing. It returns the same - // Statement or a new one. FUNCTION is the function containing this - // statement. BLOCK is the block containing this statement. - // INSERTER can be used to insert new statements before this one. - Statement* - lower(Gogo* gogo, Named_object* function, Block* block, - Statement_inserter* inserter) - { return this->do_lower(gogo, function, block, inserter); } - - // Set type information for unnamed constants. - void - determine_types(); - - // Check types in a statement. This simply checks that any - // expressions used by the statement have the right type. - void - check_types(Gogo* gogo) - { this->do_check_types(gogo); } - - // Return whether this is a block statement. - bool - is_block_statement() const - { return this->classification_ == STATEMENT_BLOCK; } - - // If this is a variable declaration statement, return it. - // Otherwise return NULL. - Variable_declaration_statement* - variable_declaration_statement() - { - return this->convert<Variable_declaration_statement, - STATEMENT_VARIABLE_DECLARATION>(); - } - - // If this is a return statement, return it. Otherwise return NULL. - Return_statement* - return_statement() - { return this->convert<Return_statement, STATEMENT_RETURN>(); } - - // If this is a thunk statement (a go or defer statement), return - // it. Otherwise return NULL. - Thunk_statement* - thunk_statement(); - - // If this is a label statement, return it. Otherwise return NULL. - Label_statement* - label_statement() - { return this->convert<Label_statement, STATEMENT_LABEL>(); } - - // If this is a for statement, return it. Otherwise return NULL. - For_statement* - for_statement() - { return this->convert<For_statement, STATEMENT_FOR>(); } - - // If this is a for statement over a range clause, return it. - // Otherwise return NULL. - For_range_statement* - for_range_statement() - { return this->convert<For_range_statement, STATEMENT_FOR_RANGE>(); } - - // If this is a switch statement, return it. Otherwise return NULL. - Switch_statement* - switch_statement() - { return this->convert<Switch_statement, STATEMENT_SWITCH>(); } - - // If this is a type switch statement, return it. Otherwise return - // NULL. - Type_switch_statement* - type_switch_statement() - { return this->convert<Type_switch_statement, STATEMENT_TYPE_SWITCH>(); } - - // If this is a select statement, return it. Otherwise return NULL. - Select_statement* - select_statement() - { return this->convert<Select_statement, STATEMENT_SELECT>(); } - - // Return true if this statement may fall through--if after - // executing this statement we may go on to execute the following - // statement, if any. - bool - may_fall_through() const - { return this->do_may_fall_through(); } - - // Convert the statement to the backend representation. - Bstatement* - get_backend(Translate_context*); - - // Dump AST representation of a statement to a dump context. - void - dump_statement(Ast_dump_context*) const; - - protected: - // Implemented by child class: traverse the tree. - virtual int - do_traverse(Traverse*) = 0; - - // Implemented by child class: traverse assignments. Any statement - // which includes an assignment should implement this. - virtual bool - do_traverse_assignments(Traverse_assignments*) - { return false; } - - // Implemented by the child class: lower this statement to a simpler - // one. - virtual Statement* - do_lower(Gogo*, Named_object*, Block*, Statement_inserter*) - { return this; } - - // Implemented by child class: set type information for unnamed - // constants. Any statement which includes an expression needs to - // implement this. - virtual void - do_determine_types() - { } - - // Implemented by child class: check types of expressions used in a - // statement. - virtual void - do_check_types(Gogo*) - { } - - // Implemented by child class: return true if this statement may - // fall through. - virtual bool - do_may_fall_through() const - { return true; } - - // Implemented by child class: convert to backend representation. - virtual Bstatement* - do_get_backend(Translate_context*) = 0; - - // Implemented by child class: dump ast representation. - virtual void - do_dump_statement(Ast_dump_context*) const = 0; - - // Traverse an expression in a statement. - int - traverse_expression(Traverse*, Expression**); - - // Traverse an expression list in a statement. The Expression_list - // may be NULL. - int - traverse_expression_list(Traverse*, Expression_list*); - - // Traverse a type in a statement. - int - traverse_type(Traverse*, Type*); - - // For children to call when they detect that they are in error. - void - set_is_error(); - - // For children to call to report an error conveniently. - void - report_error(const char*); - - // For children to return an error statement from lower(). - static Statement* - make_error_statement(Location); - - private: - // Convert to the desired statement classification, or return NULL. - // This is a controlled dynamic cast. - template<typename Statement_class, Statement_classification sc> - Statement_class* - convert() - { - return (this->classification_ == sc - ? static_cast<Statement_class*>(this) - : NULL); - } - - template<typename Statement_class, Statement_classification sc> - const Statement_class* - convert() const - { - return (this->classification_ == sc - ? static_cast<const Statement_class*>(this) - : NULL); - } - - // The statement classification. - Statement_classification classification_; - // The location in the input file of the start of this statement. - Location location_; -}; - -// A statement which creates and initializes a temporary variable. - -class Temporary_statement : public Statement -{ - public: - Temporary_statement(Type* type, Expression* init, Location location) - : Statement(STATEMENT_TEMPORARY, location), - type_(type), init_(init), bvariable_(NULL), are_hidden_fields_ok_(false), - is_address_taken_(false) - { } - - // Return the type of the temporary variable. - Type* - type() const; - - // Return the initializer if there is one. - Expression* - init() const - { return this->init_; } - - // Note that it is OK for this statement to set hidden fields. - void - set_hidden_fields_are_ok() - { this->are_hidden_fields_ok_ = true; } - - // Record that something takes the address of this temporary - // variable. - void - set_is_address_taken() - { this->is_address_taken_ = true; } - - // Return the temporary variable. This should not be called until - // after the statement itself has been converted. - Bvariable* - get_backend_variable(Translate_context*) const; - - protected: - int - do_traverse(Traverse*); - - bool - do_traverse_assignments(Traverse_assignments*); - - void - do_determine_types(); - - void - do_check_types(Gogo*); - - Bstatement* - do_get_backend(Translate_context*); - - void - do_dump_statement(Ast_dump_context*) const; - - private: - // The type of the temporary variable. - Type* type_; - // The initial value of the temporary variable. This may be NULL. - Expression* init_; - // The backend representation of the temporary variable. - Bvariable* bvariable_; - // True if this statement may set hidden fields when assigning the - // value to the temporary. This is used for generated method stubs. - bool are_hidden_fields_ok_; - // True if something takes the address of this temporary variable. - bool is_address_taken_; -}; - -// A variable declaration. This marks the point in the code where a -// variable is declared. The Variable is also attached to a Block. - -class Variable_declaration_statement : public Statement -{ - public: - Variable_declaration_statement(Named_object* var); - - // The variable being declared. - Named_object* - var() - { return this->var_; } - - protected: - int - do_traverse(Traverse*); - - bool - do_traverse_assignments(Traverse_assignments*); - - Statement* - do_lower(Gogo*, Named_object*, Block*, Statement_inserter*); - - Bstatement* - do_get_backend(Translate_context*); - - void - do_dump_statement(Ast_dump_context*) const; - - private: - Named_object* var_; -}; - -// A return statement. - -class Return_statement : public Statement -{ - public: - Return_statement(Expression_list* vals, Location location) - : Statement(STATEMENT_RETURN, location), - vals_(vals), are_hidden_fields_ok_(false), is_lowered_(false) - { } - - // The list of values being returned. This may be NULL. - const Expression_list* - vals() const - { return this->vals_; } - - // Note that it is OK for this return statement to set hidden - // fields. - void - set_hidden_fields_are_ok() - { this->are_hidden_fields_ok_ = true; } - - protected: - int - do_traverse(Traverse* traverse) - { return this->traverse_expression_list(traverse, this->vals_); } - - bool - do_traverse_assignments(Traverse_assignments*); - - Statement* - do_lower(Gogo*, Named_object*, Block*, Statement_inserter*); - - bool - do_may_fall_through() const - { return false; } - - Bstatement* - do_get_backend(Translate_context*); - - void - do_dump_statement(Ast_dump_context*) const; - - private: - // Return values. This may be NULL. - Expression_list* vals_; - // True if this statement may pass hidden fields in the return - // value. This is used for generated method stubs. - bool are_hidden_fields_ok_; - // True if this statement has been lowered. - bool is_lowered_; -}; - -// A send statement. - -class Send_statement : public Statement -{ - public: - Send_statement(Expression* channel, Expression* val, - Location location) - : Statement(STATEMENT_SEND, location), - channel_(channel), val_(val) - { } - - protected: - int - do_traverse(Traverse* traverse); - - void - do_determine_types(); - - void - do_check_types(Gogo*); - - Bstatement* - do_get_backend(Translate_context*); - - void - do_dump_statement(Ast_dump_context*) const; - - private: - // The channel on which to send the value. - Expression* channel_; - // The value to send. - Expression* val_; -}; - -// Select_clauses holds the clauses of a select statement. This is -// built by the parser. - -class Select_clauses -{ - public: - Select_clauses() - : clauses_() - { } - - // Add a new clause. IS_SEND is true if this is a send clause, - // false for a receive clause. For a send clause CHANNEL is the - // channel and VAL is the value to send. For a receive clause - // CHANNEL is the channel, VAL is either NULL or a Var_expression - // for the variable to set, and CLOSED is either NULL or a - // Var_expression to set to whether the channel is closed. If VAL - // is NULL, VAR may be a variable to be initialized with the - // received value, and CLOSEDVAR ma be a variable to be initialized - // with whether the channel is closed. IS_DEFAULT is true if this - // is the default clause. STATEMENTS is the list of statements to - // execute. - void - add(bool is_send, Expression* channel, Expression* val, Expression* closed, - Named_object* var, Named_object* closedvar, bool is_default, - Block* statements, Location location) - { - int index = static_cast<int>(this->clauses_.size()); - this->clauses_.push_back(Select_clause(index, is_send, channel, val, - closed, var, closedvar, is_default, - statements, location)); - } - - size_t - size() const - { return this->clauses_.size(); } - - // Traverse the select clauses. - int - traverse(Traverse*); - - // Lower statements. - void - lower(Gogo*, Named_object*, Block*, Temporary_statement*); - - // Determine types. - void - determine_types(); - - // Check types. - void - check_types(); - - // Whether the select clauses may fall through to the statement - // which follows the overall select statement. - bool - may_fall_through() const; - - // Convert to the backend representation. - Bstatement* - get_backend(Translate_context*, Temporary_statement* sel, - Unnamed_label* break_label, Location); - - // Dump AST representation. - void - dump_clauses(Ast_dump_context*) const; - - private: - // A single clause. - class Select_clause - { - public: - Select_clause() - : channel_(NULL), val_(NULL), closed_(NULL), var_(NULL), - closedvar_(NULL), statements_(NULL), is_send_(false), - is_default_(false) - { } - - Select_clause(int index, bool is_send, Expression* channel, - Expression* val, Expression* closed, Named_object* var, - Named_object* closedvar, bool is_default, Block* statements, - Location location) - : index_(index), channel_(channel), val_(val), closed_(closed), - var_(var), closedvar_(closedvar), statements_(statements), - location_(location), is_send_(is_send), is_default_(is_default), - is_lowered_(false) - { go_assert(is_default ? channel == NULL : channel != NULL); } - - // Return the index of this clause. - int - index() const - { return this->index_; } - - // Traverse the select clause. - int - traverse(Traverse*); - - // Lower statements. - void - lower(Gogo*, Named_object*, Block*, Temporary_statement*); - - // Determine types. - void - determine_types(); - - // Check types. - void - check_types(); - - // Return true if this is the default clause. - bool - is_default() const - { return this->is_default_; } - - // Return the channel. This will return NULL for the default - // clause. - Expression* - channel() const - { return this->channel_; } - - // Return true for a send, false for a receive. - bool - is_send() const - { - go_assert(!this->is_default_); - return this->is_send_; - } - - // Return the statements. - const Block* - statements() const - { return this->statements_; } - - // Return the location. - Location - location() const - { return this->location_; } - - // Whether this clause may fall through to the statement which - // follows the overall select statement. - bool - may_fall_through() const; - - // Convert the statements to the backend representation. - Bstatement* - get_statements_backend(Translate_context*); - - // Dump AST representation. - void - dump_clause(Ast_dump_context*) const; - - private: - void - lower_default(Block*, Expression*, Expression*); - - void - lower_send(Block*, Expression*, Expression*, Expression*); - - void - lower_recv(Gogo*, Named_object*, Block*, Expression*, Expression*, - Expression*); - - // The index of this case in the generated switch statement. - int index_; - // The channel. - Expression* channel_; - // The value to send or the lvalue to receive into. - Expression* val_; - // The lvalue to set to whether the channel is closed on a - // receive. - Expression* closed_; - // The variable to initialize, for "case a := <-ch". - Named_object* var_; - // The variable to initialize to whether the channel is closed, - // for "case a, c := <-ch". - Named_object* closedvar_; - // The statements to execute. - Block* statements_; - // The location of this clause. - Location location_; - // Whether this is a send or a receive. - bool is_send_; - // Whether this is the default. - bool is_default_; - // Whether this has been lowered. - bool is_lowered_; - }; - - typedef std::vector<Select_clause> Clauses; - - Clauses clauses_; -}; - -// A select statement. - -class Select_statement : public Statement -{ - public: - Select_statement(Location location) - : Statement(STATEMENT_SELECT, location), - clauses_(NULL), sel_(NULL), break_label_(NULL), is_lowered_(false) - { } - - // Add the clauses. - void - add_clauses(Select_clauses* clauses) - { - go_assert(this->clauses_ == NULL); - this->clauses_ = clauses; - } - - // Return the break label for this select statement. - Unnamed_label* - break_label(); - - protected: - int - do_traverse(Traverse* traverse) - { return this->clauses_->traverse(traverse); } - - Statement* - do_lower(Gogo*, Named_object*, Block*, Statement_inserter*); - - void - do_determine_types() - { this->clauses_->determine_types(); } - - void - do_check_types(Gogo*) - { this->clauses_->check_types(); } - - bool - do_may_fall_through() const - { return this->clauses_->may_fall_through(); } - - Bstatement* - do_get_backend(Translate_context*); - - void - do_dump_statement(Ast_dump_context*) const; - - private: - // The select clauses. - Select_clauses* clauses_; - // A temporary which holds the select structure we build up at runtime. - Temporary_statement* sel_; - // The break label. - Unnamed_label* break_label_; - // Whether this statement has been lowered. - bool is_lowered_; -}; - -// A statement which requires a thunk: go or defer. - -class Thunk_statement : public Statement -{ - public: - Thunk_statement(Statement_classification, Call_expression*, - Location); - - // Return the call expression. - Expression* - call() const - { return this->call_; } - - // Simplify a go or defer statement so that it only uses a single - // parameter. - bool - simplify_statement(Gogo*, Named_object*, Block*); - - protected: - int - do_traverse(Traverse* traverse); - - bool - do_traverse_assignments(Traverse_assignments*); - - void - do_determine_types(); - - void - do_check_types(Gogo*); - - // Return the function and argument for the call. - bool - get_fn_and_arg(Expression** pfn, Expression** parg); - - private: - // Return whether this is a simple go statement. - bool - is_simple(Function_type*) const; - - // Return whether the thunk function is a constant. - bool - is_constant_function() const; - - // Build the struct to use for a complex case. - Struct_type* - build_struct(Function_type* fntype); - - // Build the thunk. - void - build_thunk(Gogo*, const std::string&); - - // Set the name to use for thunk field N. - void - thunk_field_param(int n, char* buf, size_t buflen); - - // The function call to be executed in a separate thread (go) or - // later (defer). - Expression* call_; - // The type used for a struct to pass to a thunk, if this is not a - // simple call. - Struct_type* struct_type_; -}; - -// A go statement. - -class Go_statement : public Thunk_statement -{ - public: - Go_statement(Call_expression* call, Location location) - : Thunk_statement(STATEMENT_GO, call, location) - { } - - protected: - Bstatement* - do_get_backend(Translate_context*); - - void - do_dump_statement(Ast_dump_context*) const; -}; - -// A defer statement. - -class Defer_statement : public Thunk_statement -{ - public: - Defer_statement(Call_expression* call, Location location) - : Thunk_statement(STATEMENT_DEFER, call, location) - { } - - protected: - Bstatement* - do_get_backend(Translate_context*); - - void - do_dump_statement(Ast_dump_context*) const; -}; - -// A label statement. - -class Label_statement : public Statement -{ - public: - Label_statement(Label* label, Location location) - : Statement(STATEMENT_LABEL, location), - label_(label) - { } - - // Return the label itself. - const Label* - label() const - { return this->label_; } - - protected: - int - do_traverse(Traverse*); - - Bstatement* - do_get_backend(Translate_context*); - - void - do_dump_statement(Ast_dump_context*) const; - - private: - // The label. - Label* label_; -}; - -// A for statement. - -class For_statement : public Statement -{ - public: - For_statement(Block* init, Expression* cond, Block* post, - Location location) - : Statement(STATEMENT_FOR, location), - init_(init), cond_(cond), post_(post), statements_(NULL), - break_label_(NULL), continue_label_(NULL) - { } - - // Add the statements. - void - add_statements(Block* statements) - { - go_assert(this->statements_ == NULL); - this->statements_ = statements; - } - - // Return the break label for this for statement. - Unnamed_label* - break_label(); - - // Return the continue label for this for statement. - Unnamed_label* - continue_label(); - - // Set the break and continue labels for this statement. - void - set_break_continue_labels(Unnamed_label* break_label, - Unnamed_label* continue_label); - - protected: - int - do_traverse(Traverse*); - - bool - do_traverse_assignments(Traverse_assignments*) - { go_unreachable(); } - - Statement* - do_lower(Gogo*, Named_object*, Block*, Statement_inserter*); - - Bstatement* - do_get_backend(Translate_context*) - { go_unreachable(); } - - void - do_dump_statement(Ast_dump_context*) const; - - private: - // The initialization statements. This may be NULL. - Block* init_; - // The condition. This may be NULL. - Expression* cond_; - // The statements to run after each iteration. This may be NULL. - Block* post_; - // The statements in the loop itself. - Block* statements_; - // The break label, if needed. - Unnamed_label* break_label_; - // The continue label, if needed. - Unnamed_label* continue_label_; -}; - -// A for statement over a range clause. - -class For_range_statement : public Statement -{ - public: - For_range_statement(Expression* index_var, Expression* value_var, - Expression* range, Location location) - : Statement(STATEMENT_FOR_RANGE, location), - index_var_(index_var), value_var_(value_var), range_(range), - statements_(NULL), break_label_(NULL), continue_label_(NULL) - { } - - // Add the statements. - void - add_statements(Block* statements) - { - go_assert(this->statements_ == NULL); - this->statements_ = statements; - } - - // Return the break label for this for statement. - Unnamed_label* - break_label(); - - // Return the continue label for this for statement. - Unnamed_label* - continue_label(); - - protected: - int - do_traverse(Traverse*); - - bool - do_traverse_assignments(Traverse_assignments*) - { go_unreachable(); } - - Statement* - do_lower(Gogo*, Named_object*, Block*, Statement_inserter*); - - Bstatement* - do_get_backend(Translate_context*) - { go_unreachable(); } - - void - do_dump_statement(Ast_dump_context*) const; - - private: - Expression* - make_range_ref(Named_object*, Temporary_statement*, Location); - - Expression* - call_builtin(Gogo*, const char* funcname, Expression* arg, Location); - - void - lower_range_array(Gogo*, Block*, Block*, Named_object*, Temporary_statement*, - Temporary_statement*, Temporary_statement*, - Block**, Expression**, Block**, Block**); - - void - lower_range_slice(Gogo*, Block*, Block*, Named_object*, Temporary_statement*, - Temporary_statement*, Temporary_statement*, - Block**, Expression**, Block**, Block**); - - void - lower_range_string(Gogo*, Block*, Block*, Named_object*, Temporary_statement*, - Temporary_statement*, Temporary_statement*, - Block**, Expression**, Block**, Block**); - - void - lower_range_map(Gogo*, Block*, Block*, Named_object*, Temporary_statement*, - Temporary_statement*, Temporary_statement*, - Block**, Expression**, Block**, Block**); - - void - lower_range_channel(Gogo*, Block*, Block*, Named_object*, - Temporary_statement*, Temporary_statement*, - Temporary_statement*, Block**, Expression**, Block**, - Block**); - - // The variable which is set to the index value. - Expression* index_var_; - // The variable which is set to the element value. This may be - // NULL. - Expression* value_var_; - // The expression we are ranging over. - Expression* range_; - // The statements in the block. - Block* statements_; - // The break label, if needed. - Unnamed_label* break_label_; - // The continue label, if needed. - Unnamed_label* continue_label_; -}; - -// Class Case_clauses holds the clauses of a switch statement. This -// is built by the parser. - -class Case_clauses -{ - public: - Case_clauses() - : clauses_() - { } - - // Add a new clause. CASES is a list of case expressions; it may be - // NULL. IS_DEFAULT is true if this is the default case. - // STATEMENTS is a block of statements. IS_FALLTHROUGH is true if - // after the statements the case clause should fall through to the - // next clause. - void - add(Expression_list* cases, bool is_default, Block* statements, - bool is_fallthrough, Location location) - { - this->clauses_.push_back(Case_clause(cases, is_default, statements, - is_fallthrough, location)); - } - - // Return whether there are no clauses. - bool - empty() const - { return this->clauses_.empty(); } - - // Traverse the case clauses. - int - traverse(Traverse*); - - // Lower for a nonconstant switch. - void - lower(Block*, Temporary_statement*, Unnamed_label*) const; - - // Determine types of expressions. The Type parameter is the type - // of the switch value. - void - determine_types(Type*); - - // Check types. The Type parameter is the type of the switch value. - bool - check_types(Type*); - - // Return true if all the clauses are constant values. - bool - is_constant() const; - - // Return true if these clauses may fall through to the statements - // following the switch statement. - bool - may_fall_through() const; - - // Return the body of a SWITCH_EXPR when all the clauses are - // constants. - void - get_backend(Translate_context*, Unnamed_label* break_label, - std::vector<std::vector<Bexpression*> >* all_cases, - std::vector<Bstatement*>* all_statements) const; - - // Dump the AST representation to a dump context. - void - dump_clauses(Ast_dump_context*) const; - - private: - // For a constant switch we need to keep a record of constants we - // have already seen. - class Hash_integer_value; - class Eq_integer_value; - typedef Unordered_set_hash(Expression*, Hash_integer_value, - Eq_integer_value) Case_constants; - - // One case clause. - class Case_clause - { - public: - Case_clause() - : cases_(NULL), statements_(NULL), is_default_(false), - is_fallthrough_(false), location_(UNKNOWN_LOCATION) - { } - - Case_clause(Expression_list* cases, bool is_default, Block* statements, - bool is_fallthrough, Location location) - : cases_(cases), statements_(statements), is_default_(is_default), - is_fallthrough_(is_fallthrough), location_(location) - { } - - // Whether this clause falls through to the next clause. - bool - is_fallthrough() const - { return this->is_fallthrough_; } - - // Whether this is the default. - bool - is_default() const - { return this->is_default_; } - - // The location of this clause. - Location - location() const - { return this->location_; } - - // Traversal. - int - traverse(Traverse*); - - // Lower for a nonconstant switch. - void - lower(Block*, Temporary_statement*, Unnamed_label*, Unnamed_label*) const; - - // Determine types. - void - determine_types(Type*); - - // Check types. - bool - check_types(Type*); - - // Return true if all the case expressions are constant. - bool - is_constant() const; - - // Return true if this clause may fall through to execute the - // statements following the switch statement. This is not the - // same as whether this clause falls through to the next clause. - bool - may_fall_through() const; - - // Convert the case values and statements to the backend - // representation. - Bstatement* - get_backend(Translate_context*, Unnamed_label* break_label, - Case_constants*, std::vector<Bexpression*>* cases) const; - - // Dump the AST representation to a dump context. - void - dump_clause(Ast_dump_context*) const; - - private: - // The list of case expressions. - Expression_list* cases_; - // The statements to execute. - Block* statements_; - // Whether this is the default case. - bool is_default_; - // Whether this falls through after the statements. - bool is_fallthrough_; - // The location of this case clause. - Location location_; - }; - - friend class Case_clause; - - // The type of the list of clauses. - typedef std::vector<Case_clause> Clauses; - - // All the case clauses. - Clauses clauses_; -}; - -// A switch statement. - -class Switch_statement : public Statement -{ - public: - Switch_statement(Expression* val, Location location) - : Statement(STATEMENT_SWITCH, location), - val_(val), clauses_(NULL), break_label_(NULL) - { } - - // Add the clauses. - void - add_clauses(Case_clauses* clauses) - { - go_assert(this->clauses_ == NULL); - this->clauses_ = clauses; - } - - // Return the break label for this switch statement. - Unnamed_label* - break_label(); - - protected: - int - do_traverse(Traverse*); - - Statement* - do_lower(Gogo*, Named_object*, Block*, Statement_inserter*); - - Bstatement* - do_get_backend(Translate_context*) - { go_unreachable(); } - - void - do_dump_statement(Ast_dump_context*) const; - - private: - // The value to switch on. This may be NULL. - Expression* val_; - // The case clauses. - Case_clauses* clauses_; - // The break label, if needed. - Unnamed_label* break_label_; -}; - -// Class Type_case_clauses holds the clauses of a type switch -// statement. This is built by the parser. - -class Type_case_clauses -{ - public: - Type_case_clauses() - : clauses_() - { } - - // Add a new clause. TYPE is the type for this clause; it may be - // NULL. IS_FALLTHROUGH is true if this falls through to the next - // clause; in this case STATEMENTS will be NULL. IS_DEFAULT is true - // if this is the default case. STATEMENTS is a block of - // statements; it may be NULL. - void - add(Type* type, bool is_fallthrough, bool is_default, Block* statements, - Location location) - { - this->clauses_.push_back(Type_case_clause(type, is_fallthrough, is_default, - statements, location)); - } - - // Return whether there are no clauses. - bool - empty() const - { return this->clauses_.empty(); } - - // Traverse the type case clauses. - int - traverse(Traverse*); - - // Check for duplicates. - void - check_duplicates() const; - - // Lower to if and goto statements. - void - lower(Type*, Block*, Temporary_statement* descriptor_temp, - Unnamed_label* break_label) const; - - // Dump the AST representation to a dump context. - void - dump_clauses(Ast_dump_context*) const; - - private: - // One type case clause. - class Type_case_clause - { - public: - Type_case_clause() - : type_(NULL), statements_(NULL), is_default_(false), - location_(UNKNOWN_LOCATION) - { } - - Type_case_clause(Type* type, bool is_fallthrough, bool is_default, - Block* statements, Location location) - : type_(type), statements_(statements), is_fallthrough_(is_fallthrough), - is_default_(is_default), location_(location) - { } - - // The type. - Type* - type() const - { return this->type_; } - - // Whether this is the default. - bool - is_default() const - { return this->is_default_; } - - // The location of this type clause. - Location - location() const - { return this->location_; } - - // Traversal. - int - traverse(Traverse*); - - // Lower to if and goto statements. - void - lower(Type*, Block*, Temporary_statement* descriptor_temp, - Unnamed_label* break_label, Unnamed_label** stmts_label) const; - - // Dump the AST representation to a dump context. - void - dump_clause(Ast_dump_context*) const; - - private: - // The type for this type clause. - Type* type_; - // The statements to execute. - Block* statements_; - // Whether this falls through--this is true for "case T1, T2". - bool is_fallthrough_; - // Whether this is the default case. - bool is_default_; - // The location of this type case clause. - Location location_; - }; - - friend class Type_case_clause; - - // The type of the list of type clauses. - typedef std::vector<Type_case_clause> Type_clauses; - - // All the type case clauses. - Type_clauses clauses_; -}; - -// A type switch statement. - -class Type_switch_statement : public Statement -{ - public: - Type_switch_statement(Named_object* var, Expression* expr, - Location location) - : Statement(STATEMENT_TYPE_SWITCH, location), - var_(var), expr_(expr), clauses_(NULL), break_label_(NULL) - { go_assert(var == NULL || expr == NULL); } - - // Add the clauses. - void - add_clauses(Type_case_clauses* clauses) - { - go_assert(this->clauses_ == NULL); - this->clauses_ = clauses; - } - - // Return the break label for this type switch statement. - Unnamed_label* - break_label(); - - protected: - int - do_traverse(Traverse*); - - Statement* - do_lower(Gogo*, Named_object*, Block*, Statement_inserter*); - - Bstatement* - do_get_backend(Translate_context*) - { go_unreachable(); } - - void - do_dump_statement(Ast_dump_context*) const; - - private: - // The variable holding the value we are switching on. - Named_object* var_; - // The expression we are switching on if there is no variable. - Expression* expr_; - // The type case clauses. - Type_case_clauses* clauses_; - // The break label, if needed. - Unnamed_label* break_label_; -}; - -#endif // !defined(GO_STATEMENTS_H) diff --git a/gcc-4.8.1/gcc/go/gofrontend/string-dump.h b/gcc-4.8.1/gcc/go/gofrontend/string-dump.h deleted file mode 100644 index fe4807d16..000000000 --- a/gcc-4.8.1/gcc/go/gofrontend/string-dump.h +++ /dev/null @@ -1,25 +0,0 @@ -// string-dump.h -- Abstract base class for dumping strings. -*- C++ -*- - -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#ifndef GO_STRING_DUMP_H -#define GO_STRING_DUMP_H - -// This abstract class provides an interface strings for whatever purpose. -// Used for example for exporting and dumping objects. - -class String_dump -{ - public: - // Write a string. Implements the String_dump interface. - virtual void - write_string(const std::string& s) = 0; - - // Implementors should override this member, to dump a formatted c string. - virtual void - write_c_string(const char*) = 0; -}; - -#endif // GO_STRING_DUMP_H diff --git a/gcc-4.8.1/gcc/go/gofrontend/types.cc b/gcc-4.8.1/gcc/go/gofrontend/types.cc deleted file mode 100644 index 769498282..000000000 --- a/gcc-4.8.1/gcc/go/gofrontend/types.cc +++ /dev/null @@ -1,9819 +0,0 @@ -// types.cc -- Go frontend types. - -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "go-system.h" - -#include "toplev.h" -#include "intl.h" -#include "tree.h" -#include "gimple.h" -#include "real.h" -#include "convert.h" - -#include "go-c.h" -#include "gogo.h" -#include "operator.h" -#include "expressions.h" -#include "statements.h" -#include "export.h" -#include "import.h" -#include "backend.h" -#include "types.h" - -// Forward declarations so that we don't have to make types.h #include -// backend.h. - -static void -get_backend_struct_fields(Gogo* gogo, const Struct_field_list* fields, - bool use_placeholder, - std::vector<Backend::Btyped_identifier>* bfields); - -static void -get_backend_slice_fields(Gogo* gogo, Array_type* type, bool use_placeholder, - std::vector<Backend::Btyped_identifier>* bfields); - -static void -get_backend_interface_fields(Gogo* gogo, Interface_type* type, - bool use_placeholder, - std::vector<Backend::Btyped_identifier>* bfields); - -// Class Type. - -Type::Type(Type_classification classification) - : classification_(classification), btype_(NULL), type_descriptor_var_(NULL) -{ -} - -Type::~Type() -{ -} - -// Get the base type for a type--skip names and forward declarations. - -Type* -Type::base() -{ - switch (this->classification_) - { - case TYPE_NAMED: - return this->named_type()->named_base(); - case TYPE_FORWARD: - return this->forward_declaration_type()->real_type()->base(); - default: - return this; - } -} - -const Type* -Type::base() const -{ - switch (this->classification_) - { - case TYPE_NAMED: - return this->named_type()->named_base(); - case TYPE_FORWARD: - return this->forward_declaration_type()->real_type()->base(); - default: - return this; - } -} - -// Skip defined forward declarations. - -Type* -Type::forwarded() -{ - Type* t = this; - Forward_declaration_type* ftype = t->forward_declaration_type(); - while (ftype != NULL && ftype->is_defined()) - { - t = ftype->real_type(); - ftype = t->forward_declaration_type(); - } - return t; -} - -const Type* -Type::forwarded() const -{ - const Type* t = this; - const Forward_declaration_type* ftype = t->forward_declaration_type(); - while (ftype != NULL && ftype->is_defined()) - { - t = ftype->real_type(); - ftype = t->forward_declaration_type(); - } - return t; -} - -// If this is a named type, return it. Otherwise, return NULL. - -Named_type* -Type::named_type() -{ - return this->forwarded()->convert_no_base<Named_type, TYPE_NAMED>(); -} - -const Named_type* -Type::named_type() const -{ - return this->forwarded()->convert_no_base<const Named_type, TYPE_NAMED>(); -} - -// Return true if this type is not defined. - -bool -Type::is_undefined() const -{ - return this->forwarded()->forward_declaration_type() != NULL; -} - -// Return true if this is a basic type: a type which is not composed -// of other types, and is not void. - -bool -Type::is_basic_type() const -{ - switch (this->classification_) - { - case TYPE_INTEGER: - case TYPE_FLOAT: - case TYPE_COMPLEX: - case TYPE_BOOLEAN: - case TYPE_STRING: - case TYPE_NIL: - return true; - - case TYPE_ERROR: - case TYPE_VOID: - case TYPE_FUNCTION: - case TYPE_POINTER: - case TYPE_STRUCT: - case TYPE_ARRAY: - case TYPE_MAP: - case TYPE_CHANNEL: - case TYPE_INTERFACE: - return false; - - case TYPE_NAMED: - case TYPE_FORWARD: - return this->base()->is_basic_type(); - - default: - go_unreachable(); - } -} - -// Return true if this is an abstract type. - -bool -Type::is_abstract() const -{ - switch (this->classification()) - { - case TYPE_INTEGER: - return this->integer_type()->is_abstract(); - case TYPE_FLOAT: - return this->float_type()->is_abstract(); - case TYPE_COMPLEX: - return this->complex_type()->is_abstract(); - case TYPE_STRING: - return this->is_abstract_string_type(); - case TYPE_BOOLEAN: - return this->is_abstract_boolean_type(); - default: - return false; - } -} - -// Return a non-abstract version of an abstract type. - -Type* -Type::make_non_abstract_type() -{ - go_assert(this->is_abstract()); - switch (this->classification()) - { - case TYPE_INTEGER: - if (this->integer_type()->is_rune()) - return Type::lookup_integer_type("int32"); - else - return Type::lookup_integer_type("int"); - case TYPE_FLOAT: - return Type::lookup_float_type("float64"); - case TYPE_COMPLEX: - return Type::lookup_complex_type("complex128"); - case TYPE_STRING: - return Type::lookup_string_type(); - case TYPE_BOOLEAN: - return Type::lookup_bool_type(); - default: - go_unreachable(); - } -} - -// Return true if this is an error type. Don't give an error if we -// try to dereference an undefined forwarding type, as this is called -// in the parser when the type may legitimately be undefined. - -bool -Type::is_error_type() const -{ - const Type* t = this->forwarded(); - // Note that we return false for an undefined forward type. - switch (t->classification_) - { - case TYPE_ERROR: - return true; - case TYPE_NAMED: - return t->named_type()->is_named_error_type(); - default: - return false; - } -} - -// If this is a pointer type, return the type to which it points. -// Otherwise, return NULL. - -Type* -Type::points_to() const -{ - const Pointer_type* ptype = this->convert<const Pointer_type, - TYPE_POINTER>(); - return ptype == NULL ? NULL : ptype->points_to(); -} - -// Return whether this is an open array type. - -bool -Type::is_slice_type() const -{ - return this->array_type() != NULL && this->array_type()->length() == NULL; -} - -// Return whether this is the predeclared constant nil being used as a -// type. - -bool -Type::is_nil_constant_as_type() const -{ - const Type* t = this->forwarded(); - if (t->forward_declaration_type() != NULL) - { - const Named_object* no = t->forward_declaration_type()->named_object(); - if (no->is_unknown()) - no = no->unknown_value()->real_named_object(); - if (no != NULL - && no->is_const() - && no->const_value()->expr()->is_nil_expression()) - return true; - } - return false; -} - -// Traverse a type. - -int -Type::traverse(Type* type, Traverse* traverse) -{ - go_assert((traverse->traverse_mask() & Traverse::traverse_types) != 0 - || (traverse->traverse_mask() - & Traverse::traverse_expressions) != 0); - if (traverse->remember_type(type)) - { - // We have already traversed this type. - return TRAVERSE_CONTINUE; - } - if ((traverse->traverse_mask() & Traverse::traverse_types) != 0) - { - int t = traverse->type(type); - if (t == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - else if (t == TRAVERSE_SKIP_COMPONENTS) - return TRAVERSE_CONTINUE; - } - // An array type has an expression which we need to traverse if - // traverse_expressions is set. - if (type->do_traverse(traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - return TRAVERSE_CONTINUE; -} - -// Default implementation for do_traverse for child class. - -int -Type::do_traverse(Traverse*) -{ - return TRAVERSE_CONTINUE; -} - -// Return whether two types are identical. If ERRORS_ARE_IDENTICAL, -// then return true for all erroneous types; this is used to avoid -// cascading errors. If REASON is not NULL, optionally set *REASON to -// the reason the types are not identical. - -bool -Type::are_identical(const Type* t1, const Type* t2, bool errors_are_identical, - std::string* reason) -{ - if (t1 == NULL || t2 == NULL) - { - // Something is wrong. - return errors_are_identical ? true : t1 == t2; - } - - // Skip defined forward declarations. - t1 = t1->forwarded(); - t2 = t2->forwarded(); - - // Ignore aliases for purposes of type identity. - if (t1->named_type() != NULL && t1->named_type()->is_alias()) - t1 = t1->named_type()->real_type(); - if (t2->named_type() != NULL && t2->named_type()->is_alias()) - t2 = t2->named_type()->real_type(); - - if (t1 == t2) - return true; - - // An undefined forward declaration is an error. - if (t1->forward_declaration_type() != NULL - || t2->forward_declaration_type() != NULL) - return errors_are_identical; - - // Avoid cascading errors with error types. - if (t1->is_error_type() || t2->is_error_type()) - { - if (errors_are_identical) - return true; - return t1->is_error_type() && t2->is_error_type(); - } - - // Get a good reason for the sink type. Note that the sink type on - // the left hand side of an assignment is handled in are_assignable. - if (t1->is_sink_type() || t2->is_sink_type()) - { - if (reason != NULL) - *reason = "invalid use of _"; - return false; - } - - // A named type is only identical to itself. - if (t1->named_type() != NULL || t2->named_type() != NULL) - return false; - - // Check type shapes. - if (t1->classification() != t2->classification()) - return false; - - switch (t1->classification()) - { - case TYPE_VOID: - case TYPE_BOOLEAN: - case TYPE_STRING: - case TYPE_NIL: - // These types are always identical. - return true; - - case TYPE_INTEGER: - return t1->integer_type()->is_identical(t2->integer_type()); - - case TYPE_FLOAT: - return t1->float_type()->is_identical(t2->float_type()); - - case TYPE_COMPLEX: - return t1->complex_type()->is_identical(t2->complex_type()); - - case TYPE_FUNCTION: - return t1->function_type()->is_identical(t2->function_type(), - false, - errors_are_identical, - reason); - - case TYPE_POINTER: - return Type::are_identical(t1->points_to(), t2->points_to(), - errors_are_identical, reason); - - case TYPE_STRUCT: - return t1->struct_type()->is_identical(t2->struct_type(), - errors_are_identical); - - case TYPE_ARRAY: - return t1->array_type()->is_identical(t2->array_type(), - errors_are_identical); - - case TYPE_MAP: - return t1->map_type()->is_identical(t2->map_type(), - errors_are_identical); - - case TYPE_CHANNEL: - return t1->channel_type()->is_identical(t2->channel_type(), - errors_are_identical); - - case TYPE_INTERFACE: - return t1->interface_type()->is_identical(t2->interface_type(), - errors_are_identical); - - case TYPE_CALL_MULTIPLE_RESULT: - if (reason != NULL) - *reason = "invalid use of multiple-value function call"; - return false; - - default: - go_unreachable(); - } -} - -// Return true if it's OK to have a binary operation with types LHS -// and RHS. This is not used for shifts or comparisons. - -bool -Type::are_compatible_for_binop(const Type* lhs, const Type* rhs) -{ - if (Type::are_identical(lhs, rhs, true, NULL)) - return true; - - // A constant of abstract bool type may be mixed with any bool type. - if ((rhs->is_abstract_boolean_type() && lhs->is_boolean_type()) - || (lhs->is_abstract_boolean_type() && rhs->is_boolean_type())) - return true; - - // A constant of abstract string type may be mixed with any string - // type. - if ((rhs->is_abstract_string_type() && lhs->is_string_type()) - || (lhs->is_abstract_string_type() && rhs->is_string_type())) - return true; - - lhs = lhs->base(); - rhs = rhs->base(); - - // A constant of abstract integer, float, or complex type may be - // mixed with an integer, float, or complex type. - if ((rhs->is_abstract() - && (rhs->integer_type() != NULL - || rhs->float_type() != NULL - || rhs->complex_type() != NULL) - && (lhs->integer_type() != NULL - || lhs->float_type() != NULL - || lhs->complex_type() != NULL)) - || (lhs->is_abstract() - && (lhs->integer_type() != NULL - || lhs->float_type() != NULL - || lhs->complex_type() != NULL) - && (rhs->integer_type() != NULL - || rhs->float_type() != NULL - || rhs->complex_type() != NULL))) - return true; - - // The nil type may be compared to a pointer, an interface type, a - // slice type, a channel type, a map type, or a function type. - if (lhs->is_nil_type() - && (rhs->points_to() != NULL - || rhs->interface_type() != NULL - || rhs->is_slice_type() - || rhs->map_type() != NULL - || rhs->channel_type() != NULL - || rhs->function_type() != NULL)) - return true; - if (rhs->is_nil_type() - && (lhs->points_to() != NULL - || lhs->interface_type() != NULL - || lhs->is_slice_type() - || lhs->map_type() != NULL - || lhs->channel_type() != NULL - || lhs->function_type() != NULL)) - return true; - - return false; -} - -// Return true if a value with type T1 may be compared with a value of -// type T2. IS_EQUALITY_OP is true for == or !=, false for <, etc. - -bool -Type::are_compatible_for_comparison(bool is_equality_op, const Type *t1, - const Type *t2, std::string *reason) -{ - if (t1 != t2 - && !Type::are_assignable(t1, t2, NULL) - && !Type::are_assignable(t2, t1, NULL)) - { - if (reason != NULL) - *reason = "incompatible types in binary expression"; - return false; - } - - if (!is_equality_op) - { - if (t1->integer_type() == NULL - && t1->float_type() == NULL - && !t1->is_string_type()) - { - if (reason != NULL) - *reason = _("invalid comparison of non-ordered type"); - return false; - } - } - else if (t1->is_slice_type() - || t1->map_type() != NULL - || t1->function_type() != NULL - || t2->is_slice_type() - || t2->map_type() != NULL - || t2->function_type() != NULL) - { - if (!t1->is_nil_type() && !t2->is_nil_type()) - { - if (reason != NULL) - { - if (t1->is_slice_type() || t2->is_slice_type()) - *reason = _("slice can only be compared to nil"); - else if (t1->map_type() != NULL || t2->map_type() != NULL) - *reason = _("map can only be compared to nil"); - else - *reason = _("func can only be compared to nil"); - - // Match 6g error messages. - if (t1->interface_type() != NULL || t2->interface_type() != NULL) - { - char buf[200]; - snprintf(buf, sizeof buf, _("invalid operation (%s)"), - reason->c_str()); - *reason = buf; - } - } - return false; - } - } - else - { - if (!t1->is_boolean_type() - && t1->integer_type() == NULL - && t1->float_type() == NULL - && t1->complex_type() == NULL - && !t1->is_string_type() - && t1->points_to() == NULL - && t1->channel_type() == NULL - && t1->interface_type() == NULL - && t1->struct_type() == NULL - && t1->array_type() == NULL - && !t1->is_nil_type()) - { - if (reason != NULL) - *reason = _("invalid comparison of non-comparable type"); - return false; - } - - if (t1->named_type() != NULL) - return t1->named_type()->named_type_is_comparable(reason); - else if (t2->named_type() != NULL) - return t2->named_type()->named_type_is_comparable(reason); - else if (t1->struct_type() != NULL) - { - const Struct_field_list* fields = t1->struct_type()->fields(); - for (Struct_field_list::const_iterator p = fields->begin(); - p != fields->end(); - ++p) - { - if (Gogo::is_sink_name(p->field_name())) - continue; - - if (!p->type()->is_comparable()) - { - if (reason != NULL) - *reason = _("invalid comparison of non-comparable struct"); - return false; - } - } - } - else if (t1->array_type() != NULL) - { - if (t1->array_type()->length()->is_nil_expression() - || !t1->array_type()->element_type()->is_comparable()) - { - if (reason != NULL) - *reason = _("invalid comparison of non-comparable array"); - return false; - } - } - } - - return true; -} - -// Return true if a value with type RHS may be assigned to a variable -// with type LHS. If CHECK_HIDDEN_FIELDS is true, check whether any -// hidden fields are modified. If REASON is not NULL, set *REASON to -// the reason the types are not assignable. - -bool -Type::are_assignable_check_hidden(const Type* lhs, const Type* rhs, - bool check_hidden_fields, - std::string* reason) -{ - // Do some checks first. Make sure the types are defined. - if (rhs != NULL && !rhs->is_undefined()) - { - if (rhs->is_void_type()) - { - if (reason != NULL) - *reason = "non-value used as value"; - return false; - } - if (rhs->is_call_multiple_result_type()) - { - if (reason != NULL) - reason->assign(_("multiple-value function call in " - "single-value context")); - return false; - } - } - - if (lhs != NULL && !lhs->is_undefined()) - { - // Any value may be assigned to the blank identifier. - if (lhs->is_sink_type()) - return true; - - // All fields of a struct must be exported, or the assignment - // must be in the same package. - if (check_hidden_fields && rhs != NULL && !rhs->is_undefined()) - { - if (lhs->has_hidden_fields(NULL, reason) - || rhs->has_hidden_fields(NULL, reason)) - return false; - } - } - - // Identical types are assignable. - if (Type::are_identical(lhs, rhs, true, reason)) - return true; - - // The types are assignable if they have identical underlying types - // and either LHS or RHS is not a named type. - if (((lhs->named_type() != NULL && rhs->named_type() == NULL) - || (rhs->named_type() != NULL && lhs->named_type() == NULL)) - && Type::are_identical(lhs->base(), rhs->base(), true, reason)) - return true; - - // The types are assignable if LHS is an interface type and RHS - // implements the required methods. - const Interface_type* lhs_interface_type = lhs->interface_type(); - if (lhs_interface_type != NULL) - { - if (lhs_interface_type->implements_interface(rhs, reason)) - return true; - const Interface_type* rhs_interface_type = rhs->interface_type(); - if (rhs_interface_type != NULL - && lhs_interface_type->is_compatible_for_assign(rhs_interface_type, - reason)) - return true; - } - - // The type are assignable if RHS is a bidirectional channel type, - // LHS is a channel type, they have identical element types, and - // either LHS or RHS is not a named type. - if (lhs->channel_type() != NULL - && rhs->channel_type() != NULL - && rhs->channel_type()->may_send() - && rhs->channel_type()->may_receive() - && (lhs->named_type() == NULL || rhs->named_type() == NULL) - && Type::are_identical(lhs->channel_type()->element_type(), - rhs->channel_type()->element_type(), - true, - reason)) - return true; - - // The nil type may be assigned to a pointer, function, slice, map, - // channel, or interface type. - if (rhs->is_nil_type() - && (lhs->points_to() != NULL - || lhs->function_type() != NULL - || lhs->is_slice_type() - || lhs->map_type() != NULL - || lhs->channel_type() != NULL - || lhs->interface_type() != NULL)) - return true; - - // An untyped numeric constant may be assigned to a numeric type if - // it is representable in that type. - if ((rhs->is_abstract() - && (rhs->integer_type() != NULL - || rhs->float_type() != NULL - || rhs->complex_type() != NULL)) - && (lhs->integer_type() != NULL - || lhs->float_type() != NULL - || lhs->complex_type() != NULL)) - return true; - - // Give some better error messages. - if (reason != NULL && reason->empty()) - { - if (rhs->interface_type() != NULL) - reason->assign(_("need explicit conversion")); - else if (lhs->named_type() != NULL && rhs->named_type() != NULL) - { - size_t len = (lhs->named_type()->name().length() - + rhs->named_type()->name().length() - + 100); - char* buf = new char[len]; - snprintf(buf, len, _("cannot use type %s as type %s"), - rhs->named_type()->message_name().c_str(), - lhs->named_type()->message_name().c_str()); - reason->assign(buf); - delete[] buf; - } - } - - return false; -} - -// Return true if a value with type RHS may be assigned to a variable -// with type LHS. If REASON is not NULL, set *REASON to the reason -// the types are not assignable. - -bool -Type::are_assignable(const Type* lhs, const Type* rhs, std::string* reason) -{ - return Type::are_assignable_check_hidden(lhs, rhs, false, reason); -} - -// Like are_assignable but don't check for hidden fields. - -bool -Type::are_assignable_hidden_ok(const Type* lhs, const Type* rhs, - std::string* reason) -{ - return Type::are_assignable_check_hidden(lhs, rhs, false, reason); -} - -// Return true if a value with type RHS may be converted to type LHS. -// If REASON is not NULL, set *REASON to the reason the types are not -// convertible. - -bool -Type::are_convertible(const Type* lhs, const Type* rhs, std::string* reason) -{ - // The types are convertible if they are assignable. - if (Type::are_assignable(lhs, rhs, reason)) - return true; - - // The types are convertible if they have identical underlying - // types. - if ((lhs->named_type() != NULL || rhs->named_type() != NULL) - && Type::are_identical(lhs->base(), rhs->base(), true, reason)) - return true; - - // The types are convertible if they are both unnamed pointer types - // and their pointer base types have identical underlying types. - if (lhs->named_type() == NULL - && rhs->named_type() == NULL - && lhs->points_to() != NULL - && rhs->points_to() != NULL - && (lhs->points_to()->named_type() != NULL - || rhs->points_to()->named_type() != NULL) - && Type::are_identical(lhs->points_to()->base(), - rhs->points_to()->base(), - true, - reason)) - return true; - - // Integer and floating point types are convertible to each other. - if ((lhs->integer_type() != NULL || lhs->float_type() != NULL) - && (rhs->integer_type() != NULL || rhs->float_type() != NULL)) - return true; - - // Complex types are convertible to each other. - if (lhs->complex_type() != NULL && rhs->complex_type() != NULL) - return true; - - // An integer, or []byte, or []rune, may be converted to a string. - if (lhs->is_string_type()) - { - if (rhs->integer_type() != NULL) - return true; - if (rhs->is_slice_type()) - { - const Type* e = rhs->array_type()->element_type()->forwarded(); - if (e->integer_type() != NULL - && (e->integer_type()->is_byte() - || e->integer_type()->is_rune())) - return true; - } - } - - // A string may be converted to []byte or []rune. - if (rhs->is_string_type() && lhs->is_slice_type()) - { - const Type* e = lhs->array_type()->element_type()->forwarded(); - if (e->integer_type() != NULL - && (e->integer_type()->is_byte() || e->integer_type()->is_rune())) - return true; - } - - // An unsafe.Pointer type may be converted to any pointer type or to - // uintptr, and vice-versa. - if (lhs->is_unsafe_pointer_type() - && (rhs->points_to() != NULL - || (rhs->integer_type() != NULL - && rhs->forwarded() == Type::lookup_integer_type("uintptr")))) - return true; - if (rhs->is_unsafe_pointer_type() - && (lhs->points_to() != NULL - || (lhs->integer_type() != NULL - && lhs->forwarded() == Type::lookup_integer_type("uintptr")))) - return true; - - // Give a better error message. - if (reason != NULL) - { - if (reason->empty()) - *reason = "invalid type conversion"; - else - { - std::string s = "invalid type conversion ("; - s += *reason; - s += ')'; - *reason = s; - } - } - - return false; -} - -// Return whether this type has any hidden fields. This is only a -// possibility for a few types. - -bool -Type::has_hidden_fields(const Named_type* within, std::string* reason) const -{ - switch (this->forwarded()->classification_) - { - case TYPE_NAMED: - return this->named_type()->named_type_has_hidden_fields(reason); - case TYPE_STRUCT: - return this->struct_type()->struct_has_hidden_fields(within, reason); - case TYPE_ARRAY: - return this->array_type()->array_has_hidden_fields(within, reason); - default: - return false; - } -} - -// Return a hash code for the type to be used for method lookup. - -unsigned int -Type::hash_for_method(Gogo* gogo) const -{ - unsigned int ret = 0; - if (this->classification_ != TYPE_FORWARD) - ret += this->classification_; - return ret + this->do_hash_for_method(gogo); -} - -// Default implementation of do_hash_for_method. This is appropriate -// for types with no subfields. - -unsigned int -Type::do_hash_for_method(Gogo*) const -{ - return 0; -} - -// Return a hash code for a string, given a starting hash. - -unsigned int -Type::hash_string(const std::string& s, unsigned int h) -{ - const char* p = s.data(); - size_t len = s.length(); - for (; len > 0; --len) - { - h ^= *p++; - h*= 16777619; - } - return h; -} - -// A hash table mapping unnamed types to the backend representation of -// those types. - -Type::Type_btypes Type::type_btypes; - -// Return a tree representing this type. - -Btype* -Type::get_backend(Gogo* gogo) -{ - if (this->btype_ != NULL) - return this->btype_; - - if (this->forward_declaration_type() != NULL - || this->named_type() != NULL) - return this->get_btype_without_hash(gogo); - - if (this->is_error_type()) - return gogo->backend()->error_type(); - - // To avoid confusing the backend, translate all identical Go types - // to the same backend representation. We use a hash table to do - // that. There is no need to use the hash table for named types, as - // named types are only identical to themselves. - - std::pair<Type*, Type_btype_entry> val; - val.first = this; - val.second.btype = NULL; - val.second.is_placeholder = false; - std::pair<Type_btypes::iterator, bool> ins = - Type::type_btypes.insert(val); - if (!ins.second && ins.first->second.btype != NULL) - { - // Note that GOGO can be NULL here, but only when the GCC - // middle-end is asking for a frontend type. That will only - // happen for simple types, which should never require - // placeholders. - if (!ins.first->second.is_placeholder) - this->btype_ = ins.first->second.btype; - else if (gogo->named_types_are_converted()) - { - this->finish_backend(gogo, ins.first->second.btype); - ins.first->second.is_placeholder = false; - } - - return ins.first->second.btype; - } - - Btype* bt = this->get_btype_without_hash(gogo); - - if (ins.first->second.btype == NULL) - { - ins.first->second.btype = bt; - ins.first->second.is_placeholder = false; - } - else - { - // We have already created a backend representation for this - // type. This can happen when an unnamed type is defined using - // a named type which in turns uses an identical unnamed type. - // Use the tree we created earlier and ignore the one we just - // built. - if (this->btype_ == bt) - this->btype_ = ins.first->second.btype; - bt = ins.first->second.btype; - } - - return bt; -} - -// Return the backend representation for a type without looking in the -// hash table for identical types. This is used for named types, -// since a named type is never identical to any other type. - -Btype* -Type::get_btype_without_hash(Gogo* gogo) -{ - if (this->btype_ == NULL) - { - Btype* bt = this->do_get_backend(gogo); - - // For a recursive function or pointer type, we will temporarily - // return a circular pointer type during the recursion. We - // don't want to record that for a forwarding type, as it may - // confuse us later. - if (this->forward_declaration_type() != NULL - && gogo->backend()->is_circular_pointer_type(bt)) - return bt; - - if (gogo == NULL || !gogo->named_types_are_converted()) - return bt; - - this->btype_ = bt; - } - return this->btype_; -} - -// Get the backend representation of a type without forcing the -// creation of the backend representation of all supporting types. -// This will return a backend type that has the correct size but may -// be incomplete. E.g., a pointer will just be a placeholder pointer, -// and will not contain the final representation of the type to which -// it points. This is used while converting all named types to the -// backend representation, to avoid problems with indirect references -// to types which are not yet complete. When this is called, the -// sizes of all direct references (e.g., a struct field) should be -// known, but the sizes of indirect references (e.g., the type to -// which a pointer points) may not. - -Btype* -Type::get_backend_placeholder(Gogo* gogo) -{ - if (gogo->named_types_are_converted()) - return this->get_backend(gogo); - if (this->btype_ != NULL) - return this->btype_; - - Btype* bt; - switch (this->classification_) - { - case TYPE_ERROR: - case TYPE_VOID: - case TYPE_BOOLEAN: - case TYPE_INTEGER: - case TYPE_FLOAT: - case TYPE_COMPLEX: - case TYPE_STRING: - case TYPE_NIL: - // These are simple types that can just be created directly. - return this->get_backend(gogo); - - case TYPE_MAP: - case TYPE_CHANNEL: - // All maps and channels have the same backend representation. - return this->get_backend(gogo); - - case TYPE_NAMED: - case TYPE_FORWARD: - // Named types keep track of their own dependencies and manage - // their own placeholders. - return this->get_backend(gogo); - - case TYPE_INTERFACE: - if (this->interface_type()->is_empty()) - return Interface_type::get_backend_empty_interface_type(gogo); - break; - - default: - break; - } - - std::pair<Type*, Type_btype_entry> val; - val.first = this; - val.second.btype = NULL; - val.second.is_placeholder = false; - std::pair<Type_btypes::iterator, bool> ins = - Type::type_btypes.insert(val); - if (!ins.second && ins.first->second.btype != NULL) - return ins.first->second.btype; - - switch (this->classification_) - { - case TYPE_FUNCTION: - { - Location loc = this->function_type()->location(); - bt = gogo->backend()->placeholder_pointer_type("", loc, true); - } - break; - - case TYPE_POINTER: - { - Location loc = Linemap::unknown_location(); - bt = gogo->backend()->placeholder_pointer_type("", loc, false); - } - break; - - case TYPE_STRUCT: - // We don't have to make the struct itself be a placeholder. We - // are promised that we know the sizes of the struct fields. - // But we may have to use a placeholder for any particular - // struct field. - { - std::vector<Backend::Btyped_identifier> bfields; - get_backend_struct_fields(gogo, this->struct_type()->fields(), - true, &bfields); - bt = gogo->backend()->struct_type(bfields); - } - break; - - case TYPE_ARRAY: - if (this->is_slice_type()) - { - std::vector<Backend::Btyped_identifier> bfields; - get_backend_slice_fields(gogo, this->array_type(), true, &bfields); - bt = gogo->backend()->struct_type(bfields); - } - else - { - Btype* element = this->array_type()->get_backend_element(gogo, true); - Bexpression* len = this->array_type()->get_backend_length(gogo); - bt = gogo->backend()->array_type(element, len); - } - break; - - case TYPE_INTERFACE: - { - go_assert(!this->interface_type()->is_empty()); - std::vector<Backend::Btyped_identifier> bfields; - get_backend_interface_fields(gogo, this->interface_type(), true, - &bfields); - bt = gogo->backend()->struct_type(bfields); - } - break; - - case TYPE_SINK: - case TYPE_CALL_MULTIPLE_RESULT: - /* Note that various classifications were handled in the earlier - switch. */ - default: - go_unreachable(); - } - - if (ins.first->second.btype == NULL) - { - ins.first->second.btype = bt; - ins.first->second.is_placeholder = true; - } - else - { - // A placeholder for this type got created along the way. Use - // that one and ignore the one we just built. - bt = ins.first->second.btype; - } - - return bt; -} - -// Complete the backend representation. This is called for a type -// using a placeholder type. - -void -Type::finish_backend(Gogo* gogo, Btype *placeholder) -{ - switch (this->classification_) - { - case TYPE_ERROR: - case TYPE_VOID: - case TYPE_BOOLEAN: - case TYPE_INTEGER: - case TYPE_FLOAT: - case TYPE_COMPLEX: - case TYPE_STRING: - case TYPE_NIL: - go_unreachable(); - - case TYPE_FUNCTION: - { - Btype* bt = this->do_get_backend(gogo); - if (!gogo->backend()->set_placeholder_function_type(placeholder, bt)) - go_assert(saw_errors()); - } - break; - - case TYPE_POINTER: - { - Btype* bt = this->do_get_backend(gogo); - if (!gogo->backend()->set_placeholder_pointer_type(placeholder, bt)) - go_assert(saw_errors()); - } - break; - - case TYPE_STRUCT: - // The struct type itself is done, but we have to make sure that - // all the field types are converted. - this->struct_type()->finish_backend_fields(gogo); - break; - - case TYPE_ARRAY: - // The array type itself is done, but make sure the element type - // is converted. - this->array_type()->finish_backend_element(gogo); - break; - - case TYPE_MAP: - case TYPE_CHANNEL: - go_unreachable(); - - case TYPE_INTERFACE: - // The interface type itself is done, but make sure the method - // types are converted. - this->interface_type()->finish_backend_methods(gogo); - break; - - case TYPE_NAMED: - case TYPE_FORWARD: - go_unreachable(); - - case TYPE_SINK: - case TYPE_CALL_MULTIPLE_RESULT: - default: - go_unreachable(); - } - - this->btype_ = placeholder; -} - -// Return a pointer to the type descriptor for this type. - -tree -Type::type_descriptor_pointer(Gogo* gogo, Location location) -{ - Type* t = this->forwarded(); - if (t->named_type() != NULL && t->named_type()->is_alias()) - t = t->named_type()->real_type(); - if (t->type_descriptor_var_ == NULL) - { - t->make_type_descriptor_var(gogo); - go_assert(t->type_descriptor_var_ != NULL); - } - tree var_tree = var_to_tree(t->type_descriptor_var_); - if (var_tree == error_mark_node) - return error_mark_node; - return build_fold_addr_expr_loc(location.gcc_location(), var_tree); -} - -// A mapping from unnamed types to type descriptor variables. - -Type::Type_descriptor_vars Type::type_descriptor_vars; - -// Build the type descriptor for this type. - -void -Type::make_type_descriptor_var(Gogo* gogo) -{ - go_assert(this->type_descriptor_var_ == NULL); - - Named_type* nt = this->named_type(); - - // We can have multiple instances of unnamed types, but we only want - // to emit the type descriptor once. We use a hash table. This is - // not necessary for named types, as they are unique, and we store - // the type descriptor in the type itself. - Bvariable** phash = NULL; - if (nt == NULL) - { - Bvariable* bvnull = NULL; - std::pair<Type_descriptor_vars::iterator, bool> ins = - Type::type_descriptor_vars.insert(std::make_pair(this, bvnull)); - if (!ins.second) - { - // We've already build a type descriptor for this type. - this->type_descriptor_var_ = ins.first->second; - return; - } - phash = &ins.first->second; - } - - std::string var_name = this->type_descriptor_var_name(gogo, nt); - - // Build the contents of the type descriptor. - Expression* initializer = this->do_type_descriptor(gogo, NULL); - - Btype* initializer_btype = initializer->type()->get_backend(gogo); - - Location loc = nt == NULL ? Linemap::predeclared_location() : nt->location(); - - const Package* dummy; - if (this->type_descriptor_defined_elsewhere(nt, &dummy)) - { - this->type_descriptor_var_ = - gogo->backend()->immutable_struct_reference(var_name, - initializer_btype, - loc); - if (phash != NULL) - *phash = this->type_descriptor_var_; - return; - } - - // See if this type descriptor can appear in multiple packages. - bool is_common = false; - if (nt != NULL) - { - // We create the descriptor for a builtin type whenever we need - // it. - is_common = nt->is_builtin(); - } - else - { - // This is an unnamed type. The descriptor could be defined in - // any package where it is needed, and the linker will pick one - // descriptor to keep. - is_common = true; - } - - // We are going to build the type descriptor in this package. We - // must create the variable before we convert the initializer to the - // backend representation, because the initializer may refer to the - // type descriptor of this type. By setting type_descriptor_var_ we - // ensure that type_descriptor_pointer will work if called while - // converting INITIALIZER. - - this->type_descriptor_var_ = - gogo->backend()->immutable_struct(var_name, is_common, initializer_btype, - loc); - if (phash != NULL) - *phash = this->type_descriptor_var_; - - Translate_context context(gogo, NULL, NULL, NULL); - context.set_is_const(); - Bexpression* binitializer = tree_to_expr(initializer->get_tree(&context)); - - gogo->backend()->immutable_struct_set_init(this->type_descriptor_var_, - var_name, is_common, - initializer_btype, loc, - binitializer); -} - -// Return the name of the type descriptor variable. If NT is not -// NULL, use it to get the name. Otherwise this is an unnamed type. - -std::string -Type::type_descriptor_var_name(Gogo* gogo, Named_type* nt) -{ - if (nt == NULL) - return "__go_td_" + this->mangled_name(gogo); - - Named_object* no = nt->named_object(); - unsigned int index; - const Named_object* in_function = nt->in_function(&index); - std::string ret = "__go_tdn_"; - if (nt->is_builtin()) - go_assert(in_function == NULL); - else - { - const std::string& pkgpath(no->package() == NULL - ? gogo->pkgpath_symbol() - : no->package()->pkgpath_symbol()); - ret.append(pkgpath); - ret.append(1, '.'); - if (in_function != NULL) - { - ret.append(Gogo::unpack_hidden_name(in_function->name())); - ret.append(1, '.'); - if (index > 0) - { - char buf[30]; - snprintf(buf, sizeof buf, "%u", index); - ret.append(buf); - ret.append(1, '.'); - } - } - } - - // FIXME: This adds in pkgpath twice for hidden symbols, which is - // pointless. - const std::string& name(no->name()); - if (!Gogo::is_hidden_name(name)) - ret.append(name); - else - { - ret.append(1, '.'); - ret.append(Gogo::pkgpath_for_symbol(Gogo::hidden_name_pkgpath(name))); - ret.append(1, '.'); - ret.append(Gogo::unpack_hidden_name(name)); - } - - return ret; -} - -// Return true if this type descriptor is defined in a different -// package. If this returns true it sets *PACKAGE to the package. - -bool -Type::type_descriptor_defined_elsewhere(Named_type* nt, - const Package** package) -{ - if (nt != NULL) - { - if (nt->named_object()->package() != NULL) - { - // This is a named type defined in a different package. The - // type descriptor should be defined in that package. - *package = nt->named_object()->package(); - return true; - } - } - else - { - if (this->points_to() != NULL - && this->points_to()->named_type() != NULL - && this->points_to()->named_type()->named_object()->package() != NULL) - { - // This is an unnamed pointer to a named type defined in a - // different package. The descriptor should be defined in - // that package. - *package = this->points_to()->named_type()->named_object()->package(); - return true; - } - } - return false; -} - -// Return a composite literal for a type descriptor. - -Expression* -Type::type_descriptor(Gogo* gogo, Type* type) -{ - return type->do_type_descriptor(gogo, NULL); -} - -// Return a composite literal for a type descriptor with a name. - -Expression* -Type::named_type_descriptor(Gogo* gogo, Type* type, Named_type* name) -{ - go_assert(name != NULL && type->named_type() != name); - return type->do_type_descriptor(gogo, name); -} - -// Make a builtin struct type from a list of fields. The fields are -// pairs of a name and a type. - -Struct_type* -Type::make_builtin_struct_type(int nfields, ...) -{ - va_list ap; - va_start(ap, nfields); - - Location bloc = Linemap::predeclared_location(); - Struct_field_list* sfl = new Struct_field_list(); - for (int i = 0; i < nfields; i++) - { - const char* field_name = va_arg(ap, const char *); - Type* type = va_arg(ap, Type*); - sfl->push_back(Struct_field(Typed_identifier(field_name, type, bloc))); - } - - va_end(ap); - - return Type::make_struct_type(sfl, bloc); -} - -// A list of builtin named types. - -std::vector<Named_type*> Type::named_builtin_types; - -// Make a builtin named type. - -Named_type* -Type::make_builtin_named_type(const char* name, Type* type) -{ - Location bloc = Linemap::predeclared_location(); - Named_object* no = Named_object::make_type(name, NULL, type, bloc); - Named_type* ret = no->type_value(); - Type::named_builtin_types.push_back(ret); - return ret; -} - -// Convert the named builtin types. - -void -Type::convert_builtin_named_types(Gogo* gogo) -{ - for (std::vector<Named_type*>::const_iterator p = - Type::named_builtin_types.begin(); - p != Type::named_builtin_types.end(); - ++p) - { - bool r = (*p)->verify(); - go_assert(r); - (*p)->convert(gogo); - } -} - -// Return the type of a type descriptor. We should really tie this to -// runtime.Type rather than copying it. This must match commonType in -// libgo/go/runtime/type.go. - -Type* -Type::make_type_descriptor_type() -{ - static Type* ret; - if (ret == NULL) - { - Location bloc = Linemap::predeclared_location(); - - Type* uint8_type = Type::lookup_integer_type("uint8"); - Type* uint32_type = Type::lookup_integer_type("uint32"); - Type* uintptr_type = Type::lookup_integer_type("uintptr"); - Type* string_type = Type::lookup_string_type(); - Type* pointer_string_type = Type::make_pointer_type(string_type); - - // This is an unnamed version of unsafe.Pointer. Perhaps we - // should use the named version instead, although that would - // require us to create the unsafe package if it has not been - // imported. It probably doesn't matter. - Type* void_type = Type::make_void_type(); - Type* unsafe_pointer_type = Type::make_pointer_type(void_type); - - // Forward declaration for the type descriptor type. - Named_object* named_type_descriptor_type = - Named_object::make_type_declaration("commonType", NULL, bloc); - Type* ft = Type::make_forward_declaration(named_type_descriptor_type); - Type* pointer_type_descriptor_type = Type::make_pointer_type(ft); - - // The type of a method on a concrete type. - Struct_type* method_type = - Type::make_builtin_struct_type(5, - "name", pointer_string_type, - "pkgPath", pointer_string_type, - "mtyp", pointer_type_descriptor_type, - "typ", pointer_type_descriptor_type, - "tfn", unsafe_pointer_type); - Named_type* named_method_type = - Type::make_builtin_named_type("method", method_type); - - // Information for types with a name or methods. - Type* slice_named_method_type = - Type::make_array_type(named_method_type, NULL); - Struct_type* uncommon_type = - Type::make_builtin_struct_type(3, - "name", pointer_string_type, - "pkgPath", pointer_string_type, - "methods", slice_named_method_type); - Named_type* named_uncommon_type = - Type::make_builtin_named_type("uncommonType", uncommon_type); - - Type* pointer_uncommon_type = - Type::make_pointer_type(named_uncommon_type); - - // The type descriptor type. - - Typed_identifier_list* params = new Typed_identifier_list(); - params->push_back(Typed_identifier("key", unsafe_pointer_type, bloc)); - params->push_back(Typed_identifier("key_size", uintptr_type, bloc)); - - Typed_identifier_list* results = new Typed_identifier_list(); - results->push_back(Typed_identifier("", uintptr_type, bloc)); - - Type* hashfn_type = Type::make_function_type(NULL, params, results, bloc); - - params = new Typed_identifier_list(); - params->push_back(Typed_identifier("key1", unsafe_pointer_type, bloc)); - params->push_back(Typed_identifier("key2", unsafe_pointer_type, bloc)); - params->push_back(Typed_identifier("key_size", uintptr_type, bloc)); - - results = new Typed_identifier_list(); - results->push_back(Typed_identifier("", Type::lookup_bool_type(), bloc)); - - Type* equalfn_type = Type::make_function_type(NULL, params, results, - bloc); - - Struct_type* type_descriptor_type = - Type::make_builtin_struct_type(10, - "Kind", uint8_type, - "align", uint8_type, - "fieldAlign", uint8_type, - "size", uintptr_type, - "hash", uint32_type, - "hashfn", hashfn_type, - "equalfn", equalfn_type, - "string", pointer_string_type, - "", pointer_uncommon_type, - "ptrToThis", - pointer_type_descriptor_type); - - Named_type* named = Type::make_builtin_named_type("commonType", - type_descriptor_type); - - named_type_descriptor_type->set_type_value(named); - - ret = named; - } - - return ret; -} - -// Make the type of a pointer to a type descriptor as represented in -// Go. - -Type* -Type::make_type_descriptor_ptr_type() -{ - static Type* ret; - if (ret == NULL) - ret = Type::make_pointer_type(Type::make_type_descriptor_type()); - return ret; -} - -// Set *HASH_FN and *EQUAL_FN to the runtime functions which compute a -// hash code for this type and which compare whether two values of -// this type are equal. If NAME is not NULL it is the name of this -// type. HASH_FNTYPE and EQUAL_FNTYPE are the types of these -// functions, for convenience; they may be NULL. - -void -Type::type_functions(Gogo* gogo, Named_type* name, Function_type* hash_fntype, - Function_type* equal_fntype, Named_object** hash_fn, - Named_object** equal_fn) -{ - if (hash_fntype == NULL || equal_fntype == NULL) - { - Location bloc = Linemap::predeclared_location(); - - Type* uintptr_type = Type::lookup_integer_type("uintptr"); - Type* void_type = Type::make_void_type(); - Type* unsafe_pointer_type = Type::make_pointer_type(void_type); - - if (hash_fntype == NULL) - { - Typed_identifier_list* params = new Typed_identifier_list(); - params->push_back(Typed_identifier("key", unsafe_pointer_type, - bloc)); - params->push_back(Typed_identifier("key_size", uintptr_type, bloc)); - - Typed_identifier_list* results = new Typed_identifier_list(); - results->push_back(Typed_identifier("", uintptr_type, bloc)); - - hash_fntype = Type::make_function_type(NULL, params, results, bloc); - } - if (equal_fntype == NULL) - { - Typed_identifier_list* params = new Typed_identifier_list(); - params->push_back(Typed_identifier("key1", unsafe_pointer_type, - bloc)); - params->push_back(Typed_identifier("key2", unsafe_pointer_type, - bloc)); - params->push_back(Typed_identifier("key_size", uintptr_type, bloc)); - - Typed_identifier_list* results = new Typed_identifier_list(); - results->push_back(Typed_identifier("", Type::lookup_bool_type(), - bloc)); - - equal_fntype = Type::make_function_type(NULL, params, results, bloc); - } - } - - const char* hash_fnname; - const char* equal_fnname; - if (this->compare_is_identity(gogo)) - { - hash_fnname = "__go_type_hash_identity"; - equal_fnname = "__go_type_equal_identity"; - } - else if (!this->is_comparable()) - { - hash_fnname = "__go_type_hash_error"; - equal_fnname = "__go_type_equal_error"; - } - else - { - switch (this->base()->classification()) - { - case Type::TYPE_ERROR: - case Type::TYPE_VOID: - case Type::TYPE_NIL: - case Type::TYPE_FUNCTION: - case Type::TYPE_MAP: - // For these types is_comparable should have returned false. - go_unreachable(); - - case Type::TYPE_BOOLEAN: - case Type::TYPE_INTEGER: - case Type::TYPE_POINTER: - case Type::TYPE_CHANNEL: - // For these types compare_is_identity should have returned true. - go_unreachable(); - - case Type::TYPE_FLOAT: - hash_fnname = "__go_type_hash_float"; - equal_fnname = "__go_type_equal_float"; - break; - - case Type::TYPE_COMPLEX: - hash_fnname = "__go_type_hash_complex"; - equal_fnname = "__go_type_equal_complex"; - break; - - case Type::TYPE_STRING: - hash_fnname = "__go_type_hash_string"; - equal_fnname = "__go_type_equal_string"; - break; - - case Type::TYPE_STRUCT: - { - // This is a struct which can not be compared using a - // simple identity function. We need to build a function - // for comparison. - this->specific_type_functions(gogo, name, hash_fntype, - equal_fntype, hash_fn, equal_fn); - return; - } - - case Type::TYPE_ARRAY: - if (this->is_slice_type()) - { - // Type::is_compatible_for_comparison should have - // returned false. - go_unreachable(); - } - else - { - // This is an array which can not be compared using a - // simple identity function. We need to build a - // function for comparison. - this->specific_type_functions(gogo, name, hash_fntype, - equal_fntype, hash_fn, equal_fn); - return; - } - break; - - case Type::TYPE_INTERFACE: - if (this->interface_type()->is_empty()) - { - hash_fnname = "__go_type_hash_empty_interface"; - equal_fnname = "__go_type_equal_empty_interface"; - } - else - { - hash_fnname = "__go_type_hash_interface"; - equal_fnname = "__go_type_equal_interface"; - } - break; - - case Type::TYPE_NAMED: - case Type::TYPE_FORWARD: - go_unreachable(); - - default: - go_unreachable(); - } - } - - - Location bloc = Linemap::predeclared_location(); - *hash_fn = Named_object::make_function_declaration(hash_fnname, NULL, - hash_fntype, bloc); - (*hash_fn)->func_declaration_value()->set_asm_name(hash_fnname); - *equal_fn = Named_object::make_function_declaration(equal_fnname, NULL, - equal_fntype, bloc); - (*equal_fn)->func_declaration_value()->set_asm_name(equal_fnname); -} - -// A hash table mapping types to the specific hash functions. - -Type::Type_functions Type::type_functions_table; - -// Handle a type function which is specific to a type: a struct or -// array which can not use an identity comparison. - -void -Type::specific_type_functions(Gogo* gogo, Named_type* name, - Function_type* hash_fntype, - Function_type* equal_fntype, - Named_object** hash_fn, - Named_object** equal_fn) -{ - Hash_equal_fn fnull(NULL, NULL); - std::pair<Type*, Hash_equal_fn> val(name != NULL ? name : this, fnull); - std::pair<Type_functions::iterator, bool> ins = - Type::type_functions_table.insert(val); - if (!ins.second) - { - // We already have functions for this type - *hash_fn = ins.first->second.first; - *equal_fn = ins.first->second.second; - return; - } - - std::string base_name; - if (name == NULL) - { - // Mangled names can have '.' if they happen to refer to named - // types in some way. That's fine if this is simply a named - // type, but otherwise it will confuse the code that builds - // function identifiers. Remove '.' when necessary. - base_name = this->mangled_name(gogo); - size_t i; - while ((i = base_name.find('.')) != std::string::npos) - base_name[i] = '$'; - base_name = gogo->pack_hidden_name(base_name, false); - } - else - { - // This name is already hidden or not as appropriate. - base_name = name->name(); - unsigned int index; - const Named_object* in_function = name->in_function(&index); - if (in_function != NULL) - { - base_name += '$' + Gogo::unpack_hidden_name(in_function->name()); - if (index > 0) - { - char buf[30]; - snprintf(buf, sizeof buf, "%u", index); - base_name += '$'; - base_name += buf; - } - } - } - std::string hash_name = base_name + "$hash"; - std::string equal_name = base_name + "$equal"; - - Location bloc = Linemap::predeclared_location(); - - const Package* package = NULL; - bool is_defined_elsewhere = - this->type_descriptor_defined_elsewhere(name, &package); - if (is_defined_elsewhere) - { - *hash_fn = Named_object::make_function_declaration(hash_name, package, - hash_fntype, bloc); - *equal_fn = Named_object::make_function_declaration(equal_name, package, - equal_fntype, bloc); - } - else - { - *hash_fn = gogo->declare_package_function(hash_name, hash_fntype, bloc); - *equal_fn = gogo->declare_package_function(equal_name, equal_fntype, - bloc); - } - - ins.first->second.first = *hash_fn; - ins.first->second.second = *equal_fn; - - if (!is_defined_elsewhere) - { - if (gogo->in_global_scope()) - this->write_specific_type_functions(gogo, name, hash_name, hash_fntype, - equal_name, equal_fntype); - else - gogo->queue_specific_type_function(this, name, hash_name, hash_fntype, - equal_name, equal_fntype); - } -} - -// Write the hash and equality functions for a type which needs to be -// written specially. - -void -Type::write_specific_type_functions(Gogo* gogo, Named_type* name, - const std::string& hash_name, - Function_type* hash_fntype, - const std::string& equal_name, - Function_type* equal_fntype) -{ - Location bloc = Linemap::predeclared_location(); - - if (gogo->specific_type_functions_are_written()) - { - go_assert(saw_errors()); - return; - } - - Named_object* hash_fn = gogo->start_function(hash_name, hash_fntype, false, - bloc); - gogo->start_block(bloc); - - if (this->struct_type() != NULL) - this->struct_type()->write_hash_function(gogo, name, hash_fntype, - equal_fntype); - else if (this->array_type() != NULL) - this->array_type()->write_hash_function(gogo, name, hash_fntype, - equal_fntype); - else - go_unreachable(); - - Block* b = gogo->finish_block(bloc); - gogo->add_block(b, bloc); - gogo->lower_block(hash_fn, b); - gogo->finish_function(bloc); - - Named_object *equal_fn = gogo->start_function(equal_name, equal_fntype, - false, bloc); - gogo->start_block(bloc); - - if (this->struct_type() != NULL) - this->struct_type()->write_equal_function(gogo, name); - else if (this->array_type() != NULL) - this->array_type()->write_equal_function(gogo, name); - else - go_unreachable(); - - b = gogo->finish_block(bloc); - gogo->add_block(b, bloc); - gogo->lower_block(equal_fn, b); - gogo->finish_function(bloc); -} - -// Return a composite literal for the type descriptor for a plain type -// of kind RUNTIME_TYPE_KIND named NAME. - -Expression* -Type::type_descriptor_constructor(Gogo* gogo, int runtime_type_kind, - Named_type* name, const Methods* methods, - bool only_value_methods) -{ - Location bloc = Linemap::predeclared_location(); - - Type* td_type = Type::make_type_descriptor_type(); - const Struct_field_list* fields = td_type->struct_type()->fields(); - - Expression_list* vals = new Expression_list(); - vals->reserve(9); - - if (!this->has_pointer()) - runtime_type_kind |= RUNTIME_TYPE_KIND_NO_POINTERS; - Struct_field_list::const_iterator p = fields->begin(); - go_assert(p->is_field_name("Kind")); - mpz_t iv; - mpz_init_set_ui(iv, runtime_type_kind); - vals->push_back(Expression::make_integer(&iv, p->type(), bloc)); - - ++p; - go_assert(p->is_field_name("align")); - Expression::Type_info type_info = Expression::TYPE_INFO_ALIGNMENT; - vals->push_back(Expression::make_type_info(this, type_info)); - - ++p; - go_assert(p->is_field_name("fieldAlign")); - type_info = Expression::TYPE_INFO_FIELD_ALIGNMENT; - vals->push_back(Expression::make_type_info(this, type_info)); - - ++p; - go_assert(p->is_field_name("size")); - type_info = Expression::TYPE_INFO_SIZE; - vals->push_back(Expression::make_type_info(this, type_info)); - - ++p; - go_assert(p->is_field_name("hash")); - unsigned int h; - if (name != NULL) - h = name->hash_for_method(gogo); - else - h = this->hash_for_method(gogo); - mpz_set_ui(iv, h); - vals->push_back(Expression::make_integer(&iv, p->type(), bloc)); - - ++p; - go_assert(p->is_field_name("hashfn")); - Function_type* hash_fntype = p->type()->function_type(); - - ++p; - go_assert(p->is_field_name("equalfn")); - Function_type* equal_fntype = p->type()->function_type(); - - Named_object* hash_fn; - Named_object* equal_fn; - this->type_functions(gogo, name, hash_fntype, equal_fntype, &hash_fn, - &equal_fn); - vals->push_back(Expression::make_func_reference(hash_fn, NULL, bloc)); - vals->push_back(Expression::make_func_reference(equal_fn, NULL, bloc)); - - ++p; - go_assert(p->is_field_name("string")); - Expression* s = Expression::make_string((name != NULL - ? name->reflection(gogo) - : this->reflection(gogo)), - bloc); - vals->push_back(Expression::make_unary(OPERATOR_AND, s, bloc)); - - ++p; - go_assert(p->is_field_name("uncommonType")); - if (name == NULL && methods == NULL) - vals->push_back(Expression::make_nil(bloc)); - else - { - if (methods == NULL) - methods = name->methods(); - vals->push_back(this->uncommon_type_constructor(gogo, - p->type()->deref(), - name, methods, - only_value_methods)); - } - - ++p; - go_assert(p->is_field_name("ptrToThis")); - if (name == NULL) - vals->push_back(Expression::make_nil(bloc)); - else - { - Type* pt = Type::make_pointer_type(name); - vals->push_back(Expression::make_type_descriptor(pt, bloc)); - } - - ++p; - go_assert(p == fields->end()); - - mpz_clear(iv); - - return Expression::make_struct_composite_literal(td_type, vals, bloc); -} - -// Return a composite literal for the uncommon type information for -// this type. UNCOMMON_STRUCT_TYPE is the type of the uncommon type -// struct. If name is not NULL, it is the name of the type. If -// METHODS is not NULL, it is the list of methods. ONLY_VALUE_METHODS -// is true if only value methods should be included. At least one of -// NAME and METHODS must not be NULL. - -Expression* -Type::uncommon_type_constructor(Gogo* gogo, Type* uncommon_type, - Named_type* name, const Methods* methods, - bool only_value_methods) const -{ - Location bloc = Linemap::predeclared_location(); - - const Struct_field_list* fields = uncommon_type->struct_type()->fields(); - - Expression_list* vals = new Expression_list(); - vals->reserve(3); - - Struct_field_list::const_iterator p = fields->begin(); - go_assert(p->is_field_name("name")); - - ++p; - go_assert(p->is_field_name("pkgPath")); - - if (name == NULL) - { - vals->push_back(Expression::make_nil(bloc)); - vals->push_back(Expression::make_nil(bloc)); - } - else - { - Named_object* no = name->named_object(); - std::string n = Gogo::unpack_hidden_name(no->name()); - Expression* s = Expression::make_string(n, bloc); - vals->push_back(Expression::make_unary(OPERATOR_AND, s, bloc)); - - if (name->is_builtin()) - vals->push_back(Expression::make_nil(bloc)); - else - { - const Package* package = no->package(); - const std::string& pkgpath(package == NULL - ? gogo->pkgpath() - : package->pkgpath()); - n.assign(pkgpath); - unsigned int index; - const Named_object* in_function = name->in_function(&index); - if (in_function != NULL) - { - n.append(1, '.'); - n.append(Gogo::unpack_hidden_name(in_function->name())); - if (index > 0) - { - char buf[30]; - snprintf(buf, sizeof buf, "%u", index); - n.append(1, '.'); - n.append(buf); - } - } - s = Expression::make_string(n, bloc); - vals->push_back(Expression::make_unary(OPERATOR_AND, s, bloc)); - } - } - - ++p; - go_assert(p->is_field_name("methods")); - vals->push_back(this->methods_constructor(gogo, p->type(), methods, - only_value_methods)); - - ++p; - go_assert(p == fields->end()); - - Expression* r = Expression::make_struct_composite_literal(uncommon_type, - vals, bloc); - return Expression::make_unary(OPERATOR_AND, r, bloc); -} - -// Sort methods by name. - -class Sort_methods -{ - public: - bool - operator()(const std::pair<std::string, const Method*>& m1, - const std::pair<std::string, const Method*>& m2) const - { return m1.first < m2.first; } -}; - -// Return a composite literal for the type method table for this type. -// METHODS_TYPE is the type of the table, and is a slice type. -// METHODS is the list of methods. If ONLY_VALUE_METHODS is true, -// then only value methods are used. - -Expression* -Type::methods_constructor(Gogo* gogo, Type* methods_type, - const Methods* methods, - bool only_value_methods) const -{ - Location bloc = Linemap::predeclared_location(); - - std::vector<std::pair<std::string, const Method*> > smethods; - if (methods != NULL) - { - smethods.reserve(methods->count()); - for (Methods::const_iterator p = methods->begin(); - p != methods->end(); - ++p) - { - if (p->second->is_ambiguous()) - continue; - if (only_value_methods && !p->second->is_value_method()) - continue; - - // This is where we implement the magic //go:nointerface - // comment. If we saw that comment, we don't add this - // method to the type descriptor. - if (p->second->nointerface()) - continue; - - smethods.push_back(std::make_pair(p->first, p->second)); - } - } - - if (smethods.empty()) - return Expression::make_slice_composite_literal(methods_type, NULL, bloc); - - std::sort(smethods.begin(), smethods.end(), Sort_methods()); - - Type* method_type = methods_type->array_type()->element_type(); - - Expression_list* vals = new Expression_list(); - vals->reserve(smethods.size()); - for (std::vector<std::pair<std::string, const Method*> >::const_iterator p - = smethods.begin(); - p != smethods.end(); - ++p) - vals->push_back(this->method_constructor(gogo, method_type, p->first, - p->second, only_value_methods)); - - return Expression::make_slice_composite_literal(methods_type, vals, bloc); -} - -// Return a composite literal for a single method. METHOD_TYPE is the -// type of the entry. METHOD_NAME is the name of the method and M is -// the method information. - -Expression* -Type::method_constructor(Gogo*, Type* method_type, - const std::string& method_name, - const Method* m, - bool only_value_methods) const -{ - Location bloc = Linemap::predeclared_location(); - - const Struct_field_list* fields = method_type->struct_type()->fields(); - - Expression_list* vals = new Expression_list(); - vals->reserve(5); - - Struct_field_list::const_iterator p = fields->begin(); - go_assert(p->is_field_name("name")); - const std::string n = Gogo::unpack_hidden_name(method_name); - Expression* s = Expression::make_string(n, bloc); - vals->push_back(Expression::make_unary(OPERATOR_AND, s, bloc)); - - ++p; - go_assert(p->is_field_name("pkgPath")); - if (!Gogo::is_hidden_name(method_name)) - vals->push_back(Expression::make_nil(bloc)); - else - { - s = Expression::make_string(Gogo::hidden_name_pkgpath(method_name), - bloc); - vals->push_back(Expression::make_unary(OPERATOR_AND, s, bloc)); - } - - Named_object* no = (m->needs_stub_method() - ? m->stub_object() - : m->named_object()); - - Function_type* mtype; - if (no->is_function()) - mtype = no->func_value()->type(); - else - mtype = no->func_declaration_value()->type(); - go_assert(mtype->is_method()); - Type* nonmethod_type = mtype->copy_without_receiver(); - - ++p; - go_assert(p->is_field_name("mtyp")); - vals->push_back(Expression::make_type_descriptor(nonmethod_type, bloc)); - - ++p; - go_assert(p->is_field_name("typ")); - if (!only_value_methods && m->is_value_method()) - { - // This is a value method on a pointer type. Change the type of - // the method to use a pointer receiver. The implementation - // always uses a pointer receiver anyhow. - Type* rtype = mtype->receiver()->type(); - Type* prtype = Type::make_pointer_type(rtype); - Typed_identifier* receiver = - new Typed_identifier(mtype->receiver()->name(), prtype, - mtype->receiver()->location()); - mtype = Type::make_function_type(receiver, - (mtype->parameters() == NULL - ? NULL - : mtype->parameters()->copy()), - (mtype->results() == NULL - ? NULL - : mtype->results()->copy()), - mtype->location()); - } - vals->push_back(Expression::make_type_descriptor(mtype, bloc)); - - ++p; - go_assert(p->is_field_name("tfn")); - vals->push_back(Expression::make_func_reference(no, NULL, bloc)); - - ++p; - go_assert(p == fields->end()); - - return Expression::make_struct_composite_literal(method_type, vals, bloc); -} - -// Return a composite literal for the type descriptor of a plain type. -// RUNTIME_TYPE_KIND is the value of the kind field. If NAME is not -// NULL, it is the name to use as well as the list of methods. - -Expression* -Type::plain_type_descriptor(Gogo* gogo, int runtime_type_kind, - Named_type* name) -{ - return this->type_descriptor_constructor(gogo, runtime_type_kind, - name, NULL, true); -} - -// Return the type reflection string for this type. - -std::string -Type::reflection(Gogo* gogo) const -{ - std::string ret; - - // The do_reflection virtual function should set RET to the - // reflection string. - this->do_reflection(gogo, &ret); - - return ret; -} - -// Return a mangled name for the type. - -std::string -Type::mangled_name(Gogo* gogo) const -{ - std::string ret; - - // The do_mangled_name virtual function should set RET to the - // mangled name. For a composite type it should append a code for - // the composition and then call do_mangled_name on the components. - this->do_mangled_name(gogo, &ret); - - return ret; -} - -// Return whether the backend size of the type is known. - -bool -Type::is_backend_type_size_known(Gogo* gogo) -{ - switch (this->classification_) - { - case TYPE_ERROR: - case TYPE_VOID: - case TYPE_BOOLEAN: - case TYPE_INTEGER: - case TYPE_FLOAT: - case TYPE_COMPLEX: - case TYPE_STRING: - case TYPE_FUNCTION: - case TYPE_POINTER: - case TYPE_NIL: - case TYPE_MAP: - case TYPE_CHANNEL: - case TYPE_INTERFACE: - return true; - - case TYPE_STRUCT: - { - const Struct_field_list* fields = this->struct_type()->fields(); - for (Struct_field_list::const_iterator pf = fields->begin(); - pf != fields->end(); - ++pf) - if (!pf->type()->is_backend_type_size_known(gogo)) - return false; - return true; - } - - case TYPE_ARRAY: - { - const Array_type* at = this->array_type(); - if (at->length() == NULL) - return true; - else - { - Numeric_constant nc; - if (!at->length()->numeric_constant_value(&nc)) - return false; - mpz_t ival; - if (!nc.to_int(&ival)) - return false; - mpz_clear(ival); - return at->element_type()->is_backend_type_size_known(gogo); - } - } - - case TYPE_NAMED: - // Begin converting this type to the backend representation. - // This will create a placeholder if necessary. - this->get_backend(gogo); - return this->named_type()->is_named_backend_type_size_known(); - - case TYPE_FORWARD: - { - Forward_declaration_type* fdt = this->forward_declaration_type(); - return fdt->real_type()->is_backend_type_size_known(gogo); - } - - case TYPE_SINK: - case TYPE_CALL_MULTIPLE_RESULT: - go_unreachable(); - - default: - go_unreachable(); - } -} - -// If the size of the type can be determined, set *PSIZE to the size -// in bytes and return true. Otherwise, return false. This queries -// the backend. - -bool -Type::backend_type_size(Gogo* gogo, unsigned int *psize) -{ - if (!this->is_backend_type_size_known(gogo)) - return false; - Btype* bt = this->get_backend_placeholder(gogo); - size_t size = gogo->backend()->type_size(bt); - *psize = static_cast<unsigned int>(size); - if (*psize != size) - return false; - return true; -} - -// If the alignment of the type can be determined, set *PALIGN to -// the alignment in bytes and return true. Otherwise, return false. - -bool -Type::backend_type_align(Gogo* gogo, unsigned int *palign) -{ - if (!this->is_backend_type_size_known(gogo)) - return false; - Btype* bt = this->get_backend_placeholder(gogo); - size_t align = gogo->backend()->type_alignment(bt); - *palign = static_cast<unsigned int>(align); - if (*palign != align) - return false; - return true; -} - -// Like backend_type_align, but return the alignment when used as a -// field. - -bool -Type::backend_type_field_align(Gogo* gogo, unsigned int *palign) -{ - if (!this->is_backend_type_size_known(gogo)) - return false; - Btype* bt = this->get_backend_placeholder(gogo); - size_t a = gogo->backend()->type_field_alignment(bt); - *palign = static_cast<unsigned int>(a); - if (*palign != a) - return false; - return true; -} - -// Default function to export a type. - -void -Type::do_export(Export*) const -{ - go_unreachable(); -} - -// Import a type. - -Type* -Type::import_type(Import* imp) -{ - if (imp->match_c_string("(")) - return Function_type::do_import(imp); - else if (imp->match_c_string("*")) - return Pointer_type::do_import(imp); - else if (imp->match_c_string("struct ")) - return Struct_type::do_import(imp); - else if (imp->match_c_string("[")) - return Array_type::do_import(imp); - else if (imp->match_c_string("map ")) - return Map_type::do_import(imp); - else if (imp->match_c_string("chan ")) - return Channel_type::do_import(imp); - else if (imp->match_c_string("interface")) - return Interface_type::do_import(imp); - else - { - error_at(imp->location(), "import error: expected type"); - return Type::make_error_type(); - } -} - -// A type used to indicate a parsing error. This exists to simplify -// later error detection. - -class Error_type : public Type -{ - public: - Error_type() - : Type(TYPE_ERROR) - { } - - protected: - bool - do_compare_is_identity(Gogo*) - { return false; } - - Btype* - do_get_backend(Gogo* gogo) - { return gogo->backend()->error_type(); } - - Expression* - do_type_descriptor(Gogo*, Named_type*) - { return Expression::make_error(Linemap::predeclared_location()); } - - void - do_reflection(Gogo*, std::string*) const - { go_assert(saw_errors()); } - - void - do_mangled_name(Gogo*, std::string* ret) const - { ret->push_back('E'); } -}; - -Type* -Type::make_error_type() -{ - static Error_type singleton_error_type; - return &singleton_error_type; -} - -// The void type. - -class Void_type : public Type -{ - public: - Void_type() - : Type(TYPE_VOID) - { } - - protected: - bool - do_compare_is_identity(Gogo*) - { return false; } - - Btype* - do_get_backend(Gogo* gogo) - { return gogo->backend()->void_type(); } - - Expression* - do_type_descriptor(Gogo*, Named_type*) - { go_unreachable(); } - - void - do_reflection(Gogo*, std::string*) const - { } - - void - do_mangled_name(Gogo*, std::string* ret) const - { ret->push_back('v'); } -}; - -Type* -Type::make_void_type() -{ - static Void_type singleton_void_type; - return &singleton_void_type; -} - -// The boolean type. - -class Boolean_type : public Type -{ - public: - Boolean_type() - : Type(TYPE_BOOLEAN) - { } - - protected: - bool - do_compare_is_identity(Gogo*) - { return true; } - - Btype* - do_get_backend(Gogo* gogo) - { return gogo->backend()->bool_type(); } - - Expression* - do_type_descriptor(Gogo*, Named_type* name); - - // We should not be asked for the reflection string of a basic type. - void - do_reflection(Gogo*, std::string* ret) const - { ret->append("bool"); } - - void - do_mangled_name(Gogo*, std::string* ret) const - { ret->push_back('b'); } -}; - -// Make the type descriptor. - -Expression* -Boolean_type::do_type_descriptor(Gogo* gogo, Named_type* name) -{ - if (name != NULL) - return this->plain_type_descriptor(gogo, RUNTIME_TYPE_KIND_BOOL, name); - else - { - Named_object* no = gogo->lookup_global("bool"); - go_assert(no != NULL); - return Type::type_descriptor(gogo, no->type_value()); - } -} - -Type* -Type::make_boolean_type() -{ - static Boolean_type boolean_type; - return &boolean_type; -} - -// The named type "bool". - -static Named_type* named_bool_type; - -// Get the named type "bool". - -Named_type* -Type::lookup_bool_type() -{ - return named_bool_type; -} - -// Make the named type "bool". - -Named_type* -Type::make_named_bool_type() -{ - Type* bool_type = Type::make_boolean_type(); - Named_object* named_object = - Named_object::make_type("bool", NULL, bool_type, - Linemap::predeclared_location()); - Named_type* named_type = named_object->type_value(); - named_bool_type = named_type; - return named_type; -} - -// Class Integer_type. - -Integer_type::Named_integer_types Integer_type::named_integer_types; - -// Create a new integer type. Non-abstract integer types always have -// names. - -Named_type* -Integer_type::create_integer_type(const char* name, bool is_unsigned, - int bits, int runtime_type_kind) -{ - Integer_type* integer_type = new Integer_type(false, is_unsigned, bits, - runtime_type_kind); - std::string sname(name); - Named_object* named_object = - Named_object::make_type(sname, NULL, integer_type, - Linemap::predeclared_location()); - Named_type* named_type = named_object->type_value(); - std::pair<Named_integer_types::iterator, bool> ins = - Integer_type::named_integer_types.insert(std::make_pair(sname, named_type)); - go_assert(ins.second); - return named_type; -} - -// Look up an existing integer type. - -Named_type* -Integer_type::lookup_integer_type(const char* name) -{ - Named_integer_types::const_iterator p = - Integer_type::named_integer_types.find(name); - go_assert(p != Integer_type::named_integer_types.end()); - return p->second; -} - -// Create a new abstract integer type. - -Integer_type* -Integer_type::create_abstract_integer_type() -{ - static Integer_type* abstract_type; - if (abstract_type == NULL) - { - Type* int_type = Type::lookup_integer_type("int"); - abstract_type = new Integer_type(true, false, - int_type->integer_type()->bits(), - RUNTIME_TYPE_KIND_INT); - } - return abstract_type; -} - -// Create a new abstract character type. - -Integer_type* -Integer_type::create_abstract_character_type() -{ - static Integer_type* abstract_type; - if (abstract_type == NULL) - { - abstract_type = new Integer_type(true, false, 32, - RUNTIME_TYPE_KIND_INT32); - abstract_type->set_is_rune(); - } - return abstract_type; -} - -// Integer type compatibility. - -bool -Integer_type::is_identical(const Integer_type* t) const -{ - if (this->is_unsigned_ != t->is_unsigned_ || this->bits_ != t->bits_) - return false; - return this->is_abstract_ == t->is_abstract_; -} - -// Hash code. - -unsigned int -Integer_type::do_hash_for_method(Gogo*) const -{ - return ((this->bits_ << 4) - + ((this->is_unsigned_ ? 1 : 0) << 8) - + ((this->is_abstract_ ? 1 : 0) << 9)); -} - -// Convert an Integer_type to the backend representation. - -Btype* -Integer_type::do_get_backend(Gogo* gogo) -{ - if (this->is_abstract_) - { - go_assert(saw_errors()); - return gogo->backend()->error_type(); - } - return gogo->backend()->integer_type(this->is_unsigned_, this->bits_); -} - -// The type descriptor for an integer type. Integer types are always -// named. - -Expression* -Integer_type::do_type_descriptor(Gogo* gogo, Named_type* name) -{ - go_assert(name != NULL || saw_errors()); - return this->plain_type_descriptor(gogo, this->runtime_type_kind_, name); -} - -// We should not be asked for the reflection string of a basic type. - -void -Integer_type::do_reflection(Gogo*, std::string*) const -{ - go_assert(saw_errors()); -} - -// Mangled name. - -void -Integer_type::do_mangled_name(Gogo*, std::string* ret) const -{ - char buf[100]; - snprintf(buf, sizeof buf, "i%s%s%de", - this->is_abstract_ ? "a" : "", - this->is_unsigned_ ? "u" : "", - this->bits_); - ret->append(buf); -} - -// Make an integer type. - -Named_type* -Type::make_integer_type(const char* name, bool is_unsigned, int bits, - int runtime_type_kind) -{ - return Integer_type::create_integer_type(name, is_unsigned, bits, - runtime_type_kind); -} - -// Make an abstract integer type. - -Integer_type* -Type::make_abstract_integer_type() -{ - return Integer_type::create_abstract_integer_type(); -} - -// Make an abstract character type. - -Integer_type* -Type::make_abstract_character_type() -{ - return Integer_type::create_abstract_character_type(); -} - -// Look up an integer type. - -Named_type* -Type::lookup_integer_type(const char* name) -{ - return Integer_type::lookup_integer_type(name); -} - -// Class Float_type. - -Float_type::Named_float_types Float_type::named_float_types; - -// Create a new float type. Non-abstract float types always have -// names. - -Named_type* -Float_type::create_float_type(const char* name, int bits, - int runtime_type_kind) -{ - Float_type* float_type = new Float_type(false, bits, runtime_type_kind); - std::string sname(name); - Named_object* named_object = - Named_object::make_type(sname, NULL, float_type, - Linemap::predeclared_location()); - Named_type* named_type = named_object->type_value(); - std::pair<Named_float_types::iterator, bool> ins = - Float_type::named_float_types.insert(std::make_pair(sname, named_type)); - go_assert(ins.second); - return named_type; -} - -// Look up an existing float type. - -Named_type* -Float_type::lookup_float_type(const char* name) -{ - Named_float_types::const_iterator p = - Float_type::named_float_types.find(name); - go_assert(p != Float_type::named_float_types.end()); - return p->second; -} - -// Create a new abstract float type. - -Float_type* -Float_type::create_abstract_float_type() -{ - static Float_type* abstract_type; - if (abstract_type == NULL) - abstract_type = new Float_type(true, 64, RUNTIME_TYPE_KIND_FLOAT64); - return abstract_type; -} - -// Whether this type is identical with T. - -bool -Float_type::is_identical(const Float_type* t) const -{ - if (this->bits_ != t->bits_) - return false; - return this->is_abstract_ == t->is_abstract_; -} - -// Hash code. - -unsigned int -Float_type::do_hash_for_method(Gogo*) const -{ - return (this->bits_ << 4) + ((this->is_abstract_ ? 1 : 0) << 8); -} - -// Convert to the backend representation. - -Btype* -Float_type::do_get_backend(Gogo* gogo) -{ - return gogo->backend()->float_type(this->bits_); -} - -// The type descriptor for a float type. Float types are always named. - -Expression* -Float_type::do_type_descriptor(Gogo* gogo, Named_type* name) -{ - go_assert(name != NULL || saw_errors()); - return this->plain_type_descriptor(gogo, this->runtime_type_kind_, name); -} - -// We should not be asked for the reflection string of a basic type. - -void -Float_type::do_reflection(Gogo*, std::string*) const -{ - go_assert(saw_errors()); -} - -// Mangled name. - -void -Float_type::do_mangled_name(Gogo*, std::string* ret) const -{ - char buf[100]; - snprintf(buf, sizeof buf, "f%s%de", - this->is_abstract_ ? "a" : "", - this->bits_); - ret->append(buf); -} - -// Make a floating point type. - -Named_type* -Type::make_float_type(const char* name, int bits, int runtime_type_kind) -{ - return Float_type::create_float_type(name, bits, runtime_type_kind); -} - -// Make an abstract float type. - -Float_type* -Type::make_abstract_float_type() -{ - return Float_type::create_abstract_float_type(); -} - -// Look up a float type. - -Named_type* -Type::lookup_float_type(const char* name) -{ - return Float_type::lookup_float_type(name); -} - -// Class Complex_type. - -Complex_type::Named_complex_types Complex_type::named_complex_types; - -// Create a new complex type. Non-abstract complex types always have -// names. - -Named_type* -Complex_type::create_complex_type(const char* name, int bits, - int runtime_type_kind) -{ - Complex_type* complex_type = new Complex_type(false, bits, - runtime_type_kind); - std::string sname(name); - Named_object* named_object = - Named_object::make_type(sname, NULL, complex_type, - Linemap::predeclared_location()); - Named_type* named_type = named_object->type_value(); - std::pair<Named_complex_types::iterator, bool> ins = - Complex_type::named_complex_types.insert(std::make_pair(sname, - named_type)); - go_assert(ins.second); - return named_type; -} - -// Look up an existing complex type. - -Named_type* -Complex_type::lookup_complex_type(const char* name) -{ - Named_complex_types::const_iterator p = - Complex_type::named_complex_types.find(name); - go_assert(p != Complex_type::named_complex_types.end()); - return p->second; -} - -// Create a new abstract complex type. - -Complex_type* -Complex_type::create_abstract_complex_type() -{ - static Complex_type* abstract_type; - if (abstract_type == NULL) - abstract_type = new Complex_type(true, 128, RUNTIME_TYPE_KIND_COMPLEX128); - return abstract_type; -} - -// Whether this type is identical with T. - -bool -Complex_type::is_identical(const Complex_type *t) const -{ - if (this->bits_ != t->bits_) - return false; - return this->is_abstract_ == t->is_abstract_; -} - -// Hash code. - -unsigned int -Complex_type::do_hash_for_method(Gogo*) const -{ - return (this->bits_ << 4) + ((this->is_abstract_ ? 1 : 0) << 8); -} - -// Convert to the backend representation. - -Btype* -Complex_type::do_get_backend(Gogo* gogo) -{ - return gogo->backend()->complex_type(this->bits_); -} - -// The type descriptor for a complex type. Complex types are always -// named. - -Expression* -Complex_type::do_type_descriptor(Gogo* gogo, Named_type* name) -{ - go_assert(name != NULL || saw_errors()); - return this->plain_type_descriptor(gogo, this->runtime_type_kind_, name); -} - -// We should not be asked for the reflection string of a basic type. - -void -Complex_type::do_reflection(Gogo*, std::string*) const -{ - go_assert(saw_errors()); -} - -// Mangled name. - -void -Complex_type::do_mangled_name(Gogo*, std::string* ret) const -{ - char buf[100]; - snprintf(buf, sizeof buf, "c%s%de", - this->is_abstract_ ? "a" : "", - this->bits_); - ret->append(buf); -} - -// Make a complex type. - -Named_type* -Type::make_complex_type(const char* name, int bits, int runtime_type_kind) -{ - return Complex_type::create_complex_type(name, bits, runtime_type_kind); -} - -// Make an abstract complex type. - -Complex_type* -Type::make_abstract_complex_type() -{ - return Complex_type::create_abstract_complex_type(); -} - -// Look up a complex type. - -Named_type* -Type::lookup_complex_type(const char* name) -{ - return Complex_type::lookup_complex_type(name); -} - -// Class String_type. - -// Convert String_type to the backend representation. A string is a -// struct with two fields: a pointer to the characters and a length. - -Btype* -String_type::do_get_backend(Gogo* gogo) -{ - static Btype* backend_string_type; - if (backend_string_type == NULL) - { - std::vector<Backend::Btyped_identifier> fields(2); - - Type* b = gogo->lookup_global("byte")->type_value(); - Type* pb = Type::make_pointer_type(b); - - // We aren't going to get back to this field to finish the - // backend representation, so force it to be finished now. - if (!gogo->named_types_are_converted()) - { - Btype* bt = pb->get_backend_placeholder(gogo); - pb->finish_backend(gogo, bt); - } - - fields[0].name = "__data"; - fields[0].btype = pb->get_backend(gogo); - fields[0].location = Linemap::predeclared_location(); - - Type* int_type = Type::lookup_integer_type("int"); - fields[1].name = "__length"; - fields[1].btype = int_type->get_backend(gogo); - fields[1].location = fields[0].location; - - backend_string_type = gogo->backend()->struct_type(fields); - } - return backend_string_type; -} - -// Return a tree for the length of STRING. - -tree -String_type::length_tree(Gogo*, tree string) -{ - tree string_type = TREE_TYPE(string); - go_assert(TREE_CODE(string_type) == RECORD_TYPE); - tree length_field = DECL_CHAIN(TYPE_FIELDS(string_type)); - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(length_field)), - "__length") == 0); - return fold_build3(COMPONENT_REF, TREE_TYPE(length_field), string, - length_field, NULL_TREE); -} - -// Return a tree for a pointer to the bytes of STRING. - -tree -String_type::bytes_tree(Gogo*, tree string) -{ - tree string_type = TREE_TYPE(string); - go_assert(TREE_CODE(string_type) == RECORD_TYPE); - tree bytes_field = TYPE_FIELDS(string_type); - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(bytes_field)), - "__data") == 0); - return fold_build3(COMPONENT_REF, TREE_TYPE(bytes_field), string, - bytes_field, NULL_TREE); -} - -// The type descriptor for the string type. - -Expression* -String_type::do_type_descriptor(Gogo* gogo, Named_type* name) -{ - if (name != NULL) - return this->plain_type_descriptor(gogo, RUNTIME_TYPE_KIND_STRING, name); - else - { - Named_object* no = gogo->lookup_global("string"); - go_assert(no != NULL); - return Type::type_descriptor(gogo, no->type_value()); - } -} - -// We should not be asked for the reflection string of a basic type. - -void -String_type::do_reflection(Gogo*, std::string* ret) const -{ - ret->append("string"); -} - -// Mangled name of a string type. - -void -String_type::do_mangled_name(Gogo*, std::string* ret) const -{ - ret->push_back('z'); -} - -// Make a string type. - -Type* -Type::make_string_type() -{ - static String_type string_type; - return &string_type; -} - -// The named type "string". - -static Named_type* named_string_type; - -// Get the named type "string". - -Named_type* -Type::lookup_string_type() -{ - return named_string_type; -} - -// Make the named type string. - -Named_type* -Type::make_named_string_type() -{ - Type* string_type = Type::make_string_type(); - Named_object* named_object = - Named_object::make_type("string", NULL, string_type, - Linemap::predeclared_location()); - Named_type* named_type = named_object->type_value(); - named_string_type = named_type; - return named_type; -} - -// The sink type. This is the type of the blank identifier _. Any -// type may be assigned to it. - -class Sink_type : public Type -{ - public: - Sink_type() - : Type(TYPE_SINK) - { } - - protected: - bool - do_compare_is_identity(Gogo*) - { return false; } - - Btype* - do_get_backend(Gogo*) - { go_unreachable(); } - - Expression* - do_type_descriptor(Gogo*, Named_type*) - { go_unreachable(); } - - void - do_reflection(Gogo*, std::string*) const - { go_unreachable(); } - - void - do_mangled_name(Gogo*, std::string*) const - { go_unreachable(); } -}; - -// Make the sink type. - -Type* -Type::make_sink_type() -{ - static Sink_type sink_type; - return &sink_type; -} - -// Class Function_type. - -// Traversal. - -int -Function_type::do_traverse(Traverse* traverse) -{ - if (this->receiver_ != NULL - && Type::traverse(this->receiver_->type(), traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - if (this->parameters_ != NULL - && this->parameters_->traverse(traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - if (this->results_ != NULL - && this->results_->traverse(traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - return TRAVERSE_CONTINUE; -} - -// Returns whether T is a valid redeclaration of this type. If this -// returns false, and REASON is not NULL, *REASON may be set to a -// brief explanation of why it returned false. - -bool -Function_type::is_valid_redeclaration(const Function_type* t, - std::string* reason) const -{ - if (!this->is_identical(t, false, true, reason)) - return false; - - // A redeclaration of a function is required to use the same names - // for the receiver and parameters. - if (this->receiver() != NULL - && this->receiver()->name() != t->receiver()->name()) - { - if (reason != NULL) - *reason = "receiver name changed"; - return false; - } - - const Typed_identifier_list* parms1 = this->parameters(); - const Typed_identifier_list* parms2 = t->parameters(); - if (parms1 != NULL) - { - Typed_identifier_list::const_iterator p1 = parms1->begin(); - for (Typed_identifier_list::const_iterator p2 = parms2->begin(); - p2 != parms2->end(); - ++p2, ++p1) - { - if (p1->name() != p2->name()) - { - if (reason != NULL) - *reason = "parameter name changed"; - return false; - } - - // This is called at parse time, so we may have unknown - // types. - Type* t1 = p1->type()->forwarded(); - Type* t2 = p2->type()->forwarded(); - if (t1 != t2 - && t1->forward_declaration_type() != NULL - && (t2->forward_declaration_type() == NULL - || (t1->forward_declaration_type()->named_object() - != t2->forward_declaration_type()->named_object()))) - return false; - } - } - - const Typed_identifier_list* results1 = this->results(); - const Typed_identifier_list* results2 = t->results(); - if (results1 != NULL) - { - Typed_identifier_list::const_iterator res1 = results1->begin(); - for (Typed_identifier_list::const_iterator res2 = results2->begin(); - res2 != results2->end(); - ++res2, ++res1) - { - if (res1->name() != res2->name()) - { - if (reason != NULL) - *reason = "result name changed"; - return false; - } - - // This is called at parse time, so we may have unknown - // types. - Type* t1 = res1->type()->forwarded(); - Type* t2 = res2->type()->forwarded(); - if (t1 != t2 - && t1->forward_declaration_type() != NULL - && (t2->forward_declaration_type() == NULL - || (t1->forward_declaration_type()->named_object() - != t2->forward_declaration_type()->named_object()))) - return false; - } - } - - return true; -} - -// Check whether T is the same as this type. - -bool -Function_type::is_identical(const Function_type* t, bool ignore_receiver, - bool errors_are_identical, - std::string* reason) const -{ - if (!ignore_receiver) - { - const Typed_identifier* r1 = this->receiver(); - const Typed_identifier* r2 = t->receiver(); - if ((r1 != NULL) != (r2 != NULL)) - { - if (reason != NULL) - *reason = _("different receiver types"); - return false; - } - if (r1 != NULL) - { - if (!Type::are_identical(r1->type(), r2->type(), errors_are_identical, - reason)) - { - if (reason != NULL && !reason->empty()) - *reason = "receiver: " + *reason; - return false; - } - } - } - - const Typed_identifier_list* parms1 = this->parameters(); - const Typed_identifier_list* parms2 = t->parameters(); - if ((parms1 != NULL) != (parms2 != NULL)) - { - if (reason != NULL) - *reason = _("different number of parameters"); - return false; - } - if (parms1 != NULL) - { - Typed_identifier_list::const_iterator p1 = parms1->begin(); - for (Typed_identifier_list::const_iterator p2 = parms2->begin(); - p2 != parms2->end(); - ++p2, ++p1) - { - if (p1 == parms1->end()) - { - if (reason != NULL) - *reason = _("different number of parameters"); - return false; - } - - if (!Type::are_identical(p1->type(), p2->type(), - errors_are_identical, NULL)) - { - if (reason != NULL) - *reason = _("different parameter types"); - return false; - } - } - if (p1 != parms1->end()) - { - if (reason != NULL) - *reason = _("different number of parameters"); - return false; - } - } - - if (this->is_varargs() != t->is_varargs()) - { - if (reason != NULL) - *reason = _("different varargs"); - return false; - } - - const Typed_identifier_list* results1 = this->results(); - const Typed_identifier_list* results2 = t->results(); - if ((results1 != NULL) != (results2 != NULL)) - { - if (reason != NULL) - *reason = _("different number of results"); - return false; - } - if (results1 != NULL) - { - Typed_identifier_list::const_iterator res1 = results1->begin(); - for (Typed_identifier_list::const_iterator res2 = results2->begin(); - res2 != results2->end(); - ++res2, ++res1) - { - if (res1 == results1->end()) - { - if (reason != NULL) - *reason = _("different number of results"); - return false; - } - - if (!Type::are_identical(res1->type(), res2->type(), - errors_are_identical, NULL)) - { - if (reason != NULL) - *reason = _("different result types"); - return false; - } - } - if (res1 != results1->end()) - { - if (reason != NULL) - *reason = _("different number of results"); - return false; - } - } - - return true; -} - -// Hash code. - -unsigned int -Function_type::do_hash_for_method(Gogo* gogo) const -{ - unsigned int ret = 0; - // We ignore the receiver type for hash codes, because we need to - // get the same hash code for a method in an interface and a method - // declared for a type. The former will not have a receiver. - if (this->parameters_ != NULL) - { - int shift = 1; - for (Typed_identifier_list::const_iterator p = this->parameters_->begin(); - p != this->parameters_->end(); - ++p, ++shift) - ret += p->type()->hash_for_method(gogo) << shift; - } - if (this->results_ != NULL) - { - int shift = 2; - for (Typed_identifier_list::const_iterator p = this->results_->begin(); - p != this->results_->end(); - ++p, ++shift) - ret += p->type()->hash_for_method(gogo) << shift; - } - if (this->is_varargs_) - ret += 1; - ret <<= 4; - return ret; -} - -// Get the backend representation for a function type. - -Btype* -Function_type::do_get_backend(Gogo* gogo) -{ - Backend::Btyped_identifier breceiver; - if (this->receiver_ != NULL) - { - breceiver.name = Gogo::unpack_hidden_name(this->receiver_->name()); - - // We always pass the address of the receiver parameter, in - // order to make interface calls work with unknown types. - Type* rtype = this->receiver_->type(); - if (rtype->points_to() == NULL) - rtype = Type::make_pointer_type(rtype); - breceiver.btype = rtype->get_backend(gogo); - breceiver.location = this->receiver_->location(); - } - - std::vector<Backend::Btyped_identifier> bparameters; - if (this->parameters_ != NULL) - { - bparameters.resize(this->parameters_->size()); - size_t i = 0; - for (Typed_identifier_list::const_iterator p = this->parameters_->begin(); - p != this->parameters_->end(); - ++p, ++i) - { - bparameters[i].name = Gogo::unpack_hidden_name(p->name()); - bparameters[i].btype = p->type()->get_backend(gogo); - bparameters[i].location = p->location(); - } - go_assert(i == bparameters.size()); - } - - std::vector<Backend::Btyped_identifier> bresults; - if (this->results_ != NULL) - { - bresults.resize(this->results_->size()); - size_t i = 0; - for (Typed_identifier_list::const_iterator p = this->results_->begin(); - p != this->results_->end(); - ++p, ++i) - { - bresults[i].name = Gogo::unpack_hidden_name(p->name()); - bresults[i].btype = p->type()->get_backend(gogo); - bresults[i].location = p->location(); - } - go_assert(i == bresults.size()); - } - - return gogo->backend()->function_type(breceiver, bparameters, bresults, - this->location()); -} - -// The type of a function type descriptor. - -Type* -Function_type::make_function_type_descriptor_type() -{ - static Type* ret; - if (ret == NULL) - { - Type* tdt = Type::make_type_descriptor_type(); - Type* ptdt = Type::make_type_descriptor_ptr_type(); - - Type* bool_type = Type::lookup_bool_type(); - - Type* slice_type = Type::make_array_type(ptdt, NULL); - - Struct_type* s = Type::make_builtin_struct_type(4, - "", tdt, - "dotdotdot", bool_type, - "in", slice_type, - "out", slice_type); - - ret = Type::make_builtin_named_type("FuncType", s); - } - - return ret; -} - -// The type descriptor for a function type. - -Expression* -Function_type::do_type_descriptor(Gogo* gogo, Named_type* name) -{ - Location bloc = Linemap::predeclared_location(); - - Type* ftdt = Function_type::make_function_type_descriptor_type(); - - const Struct_field_list* fields = ftdt->struct_type()->fields(); - - Expression_list* vals = new Expression_list(); - vals->reserve(4); - - Struct_field_list::const_iterator p = fields->begin(); - go_assert(p->is_field_name("commonType")); - vals->push_back(this->type_descriptor_constructor(gogo, - RUNTIME_TYPE_KIND_FUNC, - name, NULL, true)); - - ++p; - go_assert(p->is_field_name("dotdotdot")); - vals->push_back(Expression::make_boolean(this->is_varargs(), bloc)); - - ++p; - go_assert(p->is_field_name("in")); - vals->push_back(this->type_descriptor_params(p->type(), this->receiver(), - this->parameters())); - - ++p; - go_assert(p->is_field_name("out")); - vals->push_back(this->type_descriptor_params(p->type(), NULL, - this->results())); - - ++p; - go_assert(p == fields->end()); - - return Expression::make_struct_composite_literal(ftdt, vals, bloc); -} - -// Return a composite literal for the parameters or results of a type -// descriptor. - -Expression* -Function_type::type_descriptor_params(Type* params_type, - const Typed_identifier* receiver, - const Typed_identifier_list* params) -{ - Location bloc = Linemap::predeclared_location(); - - if (receiver == NULL && params == NULL) - return Expression::make_slice_composite_literal(params_type, NULL, bloc); - - Expression_list* vals = new Expression_list(); - vals->reserve((params == NULL ? 0 : params->size()) - + (receiver != NULL ? 1 : 0)); - - if (receiver != NULL) - vals->push_back(Expression::make_type_descriptor(receiver->type(), bloc)); - - if (params != NULL) - { - for (Typed_identifier_list::const_iterator p = params->begin(); - p != params->end(); - ++p) - vals->push_back(Expression::make_type_descriptor(p->type(), bloc)); - } - - return Expression::make_slice_composite_literal(params_type, vals, bloc); -} - -// The reflection string. - -void -Function_type::do_reflection(Gogo* gogo, std::string* ret) const -{ - // FIXME: Turn this off until we straighten out the type of the - // struct field used in a go statement which calls a method. - // go_assert(this->receiver_ == NULL); - - ret->append("func"); - - if (this->receiver_ != NULL) - { - ret->push_back('('); - this->append_reflection(this->receiver_->type(), gogo, ret); - ret->push_back(')'); - } - - ret->push_back('('); - const Typed_identifier_list* params = this->parameters(); - if (params != NULL) - { - bool is_varargs = this->is_varargs_; - for (Typed_identifier_list::const_iterator p = params->begin(); - p != params->end(); - ++p) - { - if (p != params->begin()) - ret->append(", "); - if (!is_varargs || p + 1 != params->end()) - this->append_reflection(p->type(), gogo, ret); - else - { - ret->append("..."); - this->append_reflection(p->type()->array_type()->element_type(), - gogo, ret); - } - } - } - ret->push_back(')'); - - const Typed_identifier_list* results = this->results(); - if (results != NULL && !results->empty()) - { - if (results->size() == 1) - ret->push_back(' '); - else - ret->append(" ("); - for (Typed_identifier_list::const_iterator p = results->begin(); - p != results->end(); - ++p) - { - if (p != results->begin()) - ret->append(", "); - this->append_reflection(p->type(), gogo, ret); - } - if (results->size() > 1) - ret->push_back(')'); - } -} - -// Mangled name. - -void -Function_type::do_mangled_name(Gogo* gogo, std::string* ret) const -{ - ret->push_back('F'); - - if (this->receiver_ != NULL) - { - ret->push_back('m'); - this->append_mangled_name(this->receiver_->type(), gogo, ret); - } - - const Typed_identifier_list* params = this->parameters(); - if (params != NULL) - { - ret->push_back('p'); - for (Typed_identifier_list::const_iterator p = params->begin(); - p != params->end(); - ++p) - this->append_mangled_name(p->type(), gogo, ret); - if (this->is_varargs_) - ret->push_back('V'); - ret->push_back('e'); - } - - const Typed_identifier_list* results = this->results(); - if (results != NULL) - { - ret->push_back('r'); - for (Typed_identifier_list::const_iterator p = results->begin(); - p != results->end(); - ++p) - this->append_mangled_name(p->type(), gogo, ret); - ret->push_back('e'); - } - - ret->push_back('e'); -} - -// Export a function type. - -void -Function_type::do_export(Export* exp) const -{ - // We don't write out the receiver. The only function types which - // should have a receiver are the ones associated with explicitly - // defined methods. For those the receiver type is written out by - // Function::export_func. - - exp->write_c_string("("); - bool first = true; - if (this->parameters_ != NULL) - { - bool is_varargs = this->is_varargs_; - for (Typed_identifier_list::const_iterator p = - this->parameters_->begin(); - p != this->parameters_->end(); - ++p) - { - if (first) - first = false; - else - exp->write_c_string(", "); - exp->write_name(p->name()); - exp->write_c_string(" "); - if (!is_varargs || p + 1 != this->parameters_->end()) - exp->write_type(p->type()); - else - { - exp->write_c_string("..."); - exp->write_type(p->type()->array_type()->element_type()); - } - } - } - exp->write_c_string(")"); - - const Typed_identifier_list* results = this->results_; - if (results != NULL) - { - exp->write_c_string(" "); - if (results->size() == 1 && results->begin()->name().empty()) - exp->write_type(results->begin()->type()); - else - { - first = true; - exp->write_c_string("("); - for (Typed_identifier_list::const_iterator p = results->begin(); - p != results->end(); - ++p) - { - if (first) - first = false; - else - exp->write_c_string(", "); - exp->write_name(p->name()); - exp->write_c_string(" "); - exp->write_type(p->type()); - } - exp->write_c_string(")"); - } - } -} - -// Import a function type. - -Function_type* -Function_type::do_import(Import* imp) -{ - imp->require_c_string("("); - Typed_identifier_list* parameters; - bool is_varargs = false; - if (imp->peek_char() == ')') - parameters = NULL; - else - { - parameters = new Typed_identifier_list(); - while (true) - { - std::string name = imp->read_name(); - imp->require_c_string(" "); - - if (imp->match_c_string("...")) - { - imp->advance(3); - is_varargs = true; - } - - Type* ptype = imp->read_type(); - if (is_varargs) - ptype = Type::make_array_type(ptype, NULL); - parameters->push_back(Typed_identifier(name, ptype, - imp->location())); - if (imp->peek_char() != ',') - break; - go_assert(!is_varargs); - imp->require_c_string(", "); - } - } - imp->require_c_string(")"); - - Typed_identifier_list* results; - if (imp->peek_char() != ' ') - results = NULL; - else - { - imp->advance(1); - results = new Typed_identifier_list; - if (imp->peek_char() != '(') - { - Type* rtype = imp->read_type(); - results->push_back(Typed_identifier("", rtype, imp->location())); - } - else - { - imp->advance(1); - while (true) - { - std::string name = imp->read_name(); - imp->require_c_string(" "); - Type* rtype = imp->read_type(); - results->push_back(Typed_identifier(name, rtype, - imp->location())); - if (imp->peek_char() != ',') - break; - imp->require_c_string(", "); - } - imp->require_c_string(")"); - } - } - - Function_type* ret = Type::make_function_type(NULL, parameters, results, - imp->location()); - if (is_varargs) - ret->set_is_varargs(); - return ret; -} - -// Make a copy of a function type without a receiver. - -Function_type* -Function_type::copy_without_receiver() const -{ - go_assert(this->is_method()); - Function_type *ret = Type::make_function_type(NULL, this->parameters_, - this->results_, - this->location_); - if (this->is_varargs()) - ret->set_is_varargs(); - if (this->is_builtin()) - ret->set_is_builtin(); - return ret; -} - -// Make a copy of a function type with a receiver. - -Function_type* -Function_type::copy_with_receiver(Type* receiver_type) const -{ - go_assert(!this->is_method()); - Typed_identifier* receiver = new Typed_identifier("", receiver_type, - this->location_); - Function_type* ret = Type::make_function_type(receiver, this->parameters_, - this->results_, - this->location_); - if (this->is_varargs_) - ret->set_is_varargs(); - return ret; -} - -// Make a function type. - -Function_type* -Type::make_function_type(Typed_identifier* receiver, - Typed_identifier_list* parameters, - Typed_identifier_list* results, - Location location) -{ - return new Function_type(receiver, parameters, results, location); -} - -// Class Pointer_type. - -// Traversal. - -int -Pointer_type::do_traverse(Traverse* traverse) -{ - return Type::traverse(this->to_type_, traverse); -} - -// Hash code. - -unsigned int -Pointer_type::do_hash_for_method(Gogo* gogo) const -{ - return this->to_type_->hash_for_method(gogo) << 4; -} - -// Get the backend representation for a pointer type. - -Btype* -Pointer_type::do_get_backend(Gogo* gogo) -{ - Btype* to_btype = this->to_type_->get_backend(gogo); - return gogo->backend()->pointer_type(to_btype); -} - -// The type of a pointer type descriptor. - -Type* -Pointer_type::make_pointer_type_descriptor_type() -{ - static Type* ret; - if (ret == NULL) - { - Type* tdt = Type::make_type_descriptor_type(); - Type* ptdt = Type::make_type_descriptor_ptr_type(); - - Struct_type* s = Type::make_builtin_struct_type(2, - "", tdt, - "elem", ptdt); - - ret = Type::make_builtin_named_type("PtrType", s); - } - - return ret; -} - -// The type descriptor for a pointer type. - -Expression* -Pointer_type::do_type_descriptor(Gogo* gogo, Named_type* name) -{ - if (this->is_unsafe_pointer_type()) - { - go_assert(name != NULL); - return this->plain_type_descriptor(gogo, - RUNTIME_TYPE_KIND_UNSAFE_POINTER, - name); - } - else - { - Location bloc = Linemap::predeclared_location(); - - const Methods* methods; - Type* deref = this->points_to(); - if (deref->named_type() != NULL) - methods = deref->named_type()->methods(); - else if (deref->struct_type() != NULL) - methods = deref->struct_type()->methods(); - else - methods = NULL; - - Type* ptr_tdt = Pointer_type::make_pointer_type_descriptor_type(); - - const Struct_field_list* fields = ptr_tdt->struct_type()->fields(); - - Expression_list* vals = new Expression_list(); - vals->reserve(2); - - Struct_field_list::const_iterator p = fields->begin(); - go_assert(p->is_field_name("commonType")); - vals->push_back(this->type_descriptor_constructor(gogo, - RUNTIME_TYPE_KIND_PTR, - name, methods, false)); - - ++p; - go_assert(p->is_field_name("elem")); - vals->push_back(Expression::make_type_descriptor(deref, bloc)); - - return Expression::make_struct_composite_literal(ptr_tdt, vals, bloc); - } -} - -// Reflection string. - -void -Pointer_type::do_reflection(Gogo* gogo, std::string* ret) const -{ - ret->push_back('*'); - this->append_reflection(this->to_type_, gogo, ret); -} - -// Mangled name. - -void -Pointer_type::do_mangled_name(Gogo* gogo, std::string* ret) const -{ - ret->push_back('p'); - this->append_mangled_name(this->to_type_, gogo, ret); -} - -// Export. - -void -Pointer_type::do_export(Export* exp) const -{ - exp->write_c_string("*"); - if (this->is_unsafe_pointer_type()) - exp->write_c_string("any"); - else - exp->write_type(this->to_type_); -} - -// Import. - -Pointer_type* -Pointer_type::do_import(Import* imp) -{ - imp->require_c_string("*"); - if (imp->match_c_string("any")) - { - imp->advance(3); - return Type::make_pointer_type(Type::make_void_type()); - } - Type* to = imp->read_type(); - return Type::make_pointer_type(to); -} - -// Make a pointer type. - -Pointer_type* -Type::make_pointer_type(Type* to_type) -{ - typedef Unordered_map(Type*, Pointer_type*) Hashtable; - static Hashtable pointer_types; - Hashtable::const_iterator p = pointer_types.find(to_type); - if (p != pointer_types.end()) - return p->second; - Pointer_type* ret = new Pointer_type(to_type); - pointer_types[to_type] = ret; - return ret; -} - -// The nil type. We use a special type for nil because it is not the -// same as any other type. In C term nil has type void*, but there is -// no such type in Go. - -class Nil_type : public Type -{ - public: - Nil_type() - : Type(TYPE_NIL) - { } - - protected: - bool - do_compare_is_identity(Gogo*) - { return false; } - - Btype* - do_get_backend(Gogo* gogo) - { return gogo->backend()->pointer_type(gogo->backend()->void_type()); } - - Expression* - do_type_descriptor(Gogo*, Named_type*) - { go_unreachable(); } - - void - do_reflection(Gogo*, std::string*) const - { go_unreachable(); } - - void - do_mangled_name(Gogo*, std::string* ret) const - { ret->push_back('n'); } -}; - -// Make the nil type. - -Type* -Type::make_nil_type() -{ - static Nil_type singleton_nil_type; - return &singleton_nil_type; -} - -// The type of a function call which returns multiple values. This is -// really a struct, but we don't want to confuse a function call which -// returns a struct with a function call which returns multiple -// values. - -class Call_multiple_result_type : public Type -{ - public: - Call_multiple_result_type(Call_expression* call) - : Type(TYPE_CALL_MULTIPLE_RESULT), - call_(call) - { } - - protected: - bool - do_has_pointer() const - { - go_assert(saw_errors()); - return false; - } - - bool - do_compare_is_identity(Gogo*) - { return false; } - - Btype* - do_get_backend(Gogo* gogo) - { - go_assert(saw_errors()); - return gogo->backend()->error_type(); - } - - Expression* - do_type_descriptor(Gogo*, Named_type*) - { - go_assert(saw_errors()); - return Expression::make_error(Linemap::unknown_location()); - } - - void - do_reflection(Gogo*, std::string*) const - { go_assert(saw_errors()); } - - void - do_mangled_name(Gogo*, std::string*) const - { go_assert(saw_errors()); } - - private: - // The expression being called. - Call_expression* call_; -}; - -// Make a call result type. - -Type* -Type::make_call_multiple_result_type(Call_expression* call) -{ - return new Call_multiple_result_type(call); -} - -// Class Struct_field. - -// Get the name of a field. - -const std::string& -Struct_field::field_name() const -{ - const std::string& name(this->typed_identifier_.name()); - if (!name.empty()) - return name; - else - { - // This is called during parsing, before anything is lowered, so - // we have to be pretty careful to avoid dereferencing an - // unknown type name. - Type* t = this->typed_identifier_.type(); - Type* dt = t; - if (t->classification() == Type::TYPE_POINTER) - { - // Very ugly. - Pointer_type* ptype = static_cast<Pointer_type*>(t); - dt = ptype->points_to(); - } - if (dt->forward_declaration_type() != NULL) - return dt->forward_declaration_type()->name(); - else if (dt->named_type() != NULL) - return dt->named_type()->name(); - else if (t->is_error_type() || dt->is_error_type()) - { - static const std::string error_string = "*error*"; - return error_string; - } - else - { - // Avoid crashing in the erroneous case where T is named but - // DT is not. - go_assert(t != dt); - if (t->forward_declaration_type() != NULL) - return t->forward_declaration_type()->name(); - else if (t->named_type() != NULL) - return t->named_type()->name(); - else - go_unreachable(); - } - } -} - -// Return whether this field is named NAME. - -bool -Struct_field::is_field_name(const std::string& name) const -{ - const std::string& me(this->typed_identifier_.name()); - if (!me.empty()) - return me == name; - else - { - Type* t = this->typed_identifier_.type(); - if (t->points_to() != NULL) - t = t->points_to(); - Named_type* nt = t->named_type(); - if (nt != NULL && nt->name() == name) - return true; - - // This is a horrible hack caused by the fact that we don't pack - // the names of builtin types. FIXME. - if (nt != NULL - && nt->is_builtin() - && nt->name() == Gogo::unpack_hidden_name(name)) - return true; - - return false; - } -} - -// Class Struct_type. - -// A hash table used to find identical unnamed structs so that they -// share method tables. - -Struct_type::Identical_structs Struct_type::identical_structs; - -// Traversal. - -int -Struct_type::do_traverse(Traverse* traverse) -{ - Struct_field_list* fields = this->fields_; - if (fields != NULL) - { - for (Struct_field_list::iterator p = fields->begin(); - p != fields->end(); - ++p) - { - if (Type::traverse(p->type(), traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - } - return TRAVERSE_CONTINUE; -} - -// Verify that the struct type is complete and valid. - -bool -Struct_type::do_verify() -{ - Struct_field_list* fields = this->fields_; - if (fields == NULL) - return true; - for (Struct_field_list::iterator p = fields->begin(); - p != fields->end(); - ++p) - { - Type* t = p->type(); - if (t->is_undefined()) - { - error_at(p->location(), "struct field type is incomplete"); - p->set_type(Type::make_error_type()); - } - else if (p->is_anonymous()) - { - if (t->named_type() != NULL && t->points_to() != NULL) - { - error_at(p->location(), "embedded type may not be a pointer"); - p->set_type(Type::make_error_type()); - } - else if (t->points_to() != NULL - && t->points_to()->interface_type() != NULL) - { - error_at(p->location(), - "embedded type may not be pointer to interface"); - p->set_type(Type::make_error_type()); - } - } - } - return true; -} - -// Whether this contains a pointer. - -bool -Struct_type::do_has_pointer() const -{ - const Struct_field_list* fields = this->fields(); - if (fields == NULL) - return false; - for (Struct_field_list::const_iterator p = fields->begin(); - p != fields->end(); - ++p) - { - if (p->type()->has_pointer()) - return true; - } - return false; -} - -// Whether this type is identical to T. - -bool -Struct_type::is_identical(const Struct_type* t, - bool errors_are_identical) const -{ - const Struct_field_list* fields1 = this->fields(); - const Struct_field_list* fields2 = t->fields(); - if (fields1 == NULL || fields2 == NULL) - return fields1 == fields2; - Struct_field_list::const_iterator pf2 = fields2->begin(); - for (Struct_field_list::const_iterator pf1 = fields1->begin(); - pf1 != fields1->end(); - ++pf1, ++pf2) - { - if (pf2 == fields2->end()) - return false; - if (pf1->field_name() != pf2->field_name()) - return false; - if (pf1->is_anonymous() != pf2->is_anonymous() - || !Type::are_identical(pf1->type(), pf2->type(), - errors_are_identical, NULL)) - return false; - if (!pf1->has_tag()) - { - if (pf2->has_tag()) - return false; - } - else - { - if (!pf2->has_tag()) - return false; - if (pf1->tag() != pf2->tag()) - return false; - } - } - if (pf2 != fields2->end()) - return false; - return true; -} - -// Whether this struct type has any hidden fields. - -bool -Struct_type::struct_has_hidden_fields(const Named_type* within, - std::string* reason) const -{ - const Struct_field_list* fields = this->fields(); - if (fields == NULL) - return false; - const Package* within_package = (within == NULL - ? NULL - : within->named_object()->package()); - for (Struct_field_list::const_iterator pf = fields->begin(); - pf != fields->end(); - ++pf) - { - if (within_package != NULL - && !pf->is_anonymous() - && Gogo::is_hidden_name(pf->field_name())) - { - if (reason != NULL) - { - std::string within_name = within->named_object()->message_name(); - std::string name = Gogo::message_name(pf->field_name()); - size_t bufsize = 200 + within_name.length() + name.length(); - char* buf = new char[bufsize]; - snprintf(buf, bufsize, - _("implicit assignment of %s%s%s hidden field %s%s%s"), - open_quote, within_name.c_str(), close_quote, - open_quote, name.c_str(), close_quote); - reason->assign(buf); - delete[] buf; - } - return true; - } - - if (pf->type()->has_hidden_fields(within, reason)) - return true; - } - - return false; -} - -// Whether comparisons of this struct type are simple identity -// comparisons. - -bool -Struct_type::do_compare_is_identity(Gogo* gogo) -{ - const Struct_field_list* fields = this->fields_; - if (fields == NULL) - return true; - unsigned int offset = 0; - for (Struct_field_list::const_iterator pf = fields->begin(); - pf != fields->end(); - ++pf) - { - if (Gogo::is_sink_name(pf->field_name())) - return false; - - if (!pf->type()->compare_is_identity(gogo)) - return false; - - unsigned int field_align; - if (!pf->type()->backend_type_align(gogo, &field_align)) - return false; - if ((offset & (field_align - 1)) != 0) - { - // This struct has padding. We don't guarantee that that - // padding is zero-initialized for a stack variable, so we - // can't use memcmp to compare struct values. - return false; - } - - unsigned int field_size; - if (!pf->type()->backend_type_size(gogo, &field_size)) - return false; - offset += field_size; - } - - unsigned int struct_size; - if (!this->backend_type_size(gogo, &struct_size)) - return false; - if (offset != struct_size) - { - // Trailing padding may not be zero when on the stack. - return false; - } - - return true; -} - -// Build identity and hash functions for this struct. - -// Hash code. - -unsigned int -Struct_type::do_hash_for_method(Gogo* gogo) const -{ - unsigned int ret = 0; - if (this->fields() != NULL) - { - for (Struct_field_list::const_iterator pf = this->fields()->begin(); - pf != this->fields()->end(); - ++pf) - ret = (ret << 1) + pf->type()->hash_for_method(gogo); - } - return ret <<= 2; -} - -// Find the local field NAME. - -const Struct_field* -Struct_type::find_local_field(const std::string& name, - unsigned int *pindex) const -{ - const Struct_field_list* fields = this->fields_; - if (fields == NULL) - return NULL; - unsigned int i = 0; - for (Struct_field_list::const_iterator pf = fields->begin(); - pf != fields->end(); - ++pf, ++i) - { - if (pf->is_field_name(name)) - { - if (pindex != NULL) - *pindex = i; - return &*pf; - } - } - return NULL; -} - -// Return an expression for field NAME in STRUCT_EXPR, or NULL. - -Field_reference_expression* -Struct_type::field_reference(Expression* struct_expr, const std::string& name, - Location location) const -{ - unsigned int depth; - return this->field_reference_depth(struct_expr, name, location, NULL, - &depth); -} - -// Return an expression for a field, along with the depth at which it -// was found. - -Field_reference_expression* -Struct_type::field_reference_depth(Expression* struct_expr, - const std::string& name, - Location location, - Saw_named_type* saw, - unsigned int* depth) const -{ - const Struct_field_list* fields = this->fields_; - if (fields == NULL) - return NULL; - - // Look for a field with this name. - unsigned int i = 0; - for (Struct_field_list::const_iterator pf = fields->begin(); - pf != fields->end(); - ++pf, ++i) - { - if (pf->is_field_name(name)) - { - *depth = 0; - return Expression::make_field_reference(struct_expr, i, location); - } - } - - // Look for an anonymous field which contains a field with this - // name. - unsigned int found_depth = 0; - Field_reference_expression* ret = NULL; - i = 0; - for (Struct_field_list::const_iterator pf = fields->begin(); - pf != fields->end(); - ++pf, ++i) - { - if (!pf->is_anonymous()) - continue; - - Struct_type* st = pf->type()->deref()->struct_type(); - if (st == NULL) - continue; - - Saw_named_type* hold_saw = saw; - Saw_named_type saw_here; - Named_type* nt = pf->type()->named_type(); - if (nt == NULL) - nt = pf->type()->deref()->named_type(); - if (nt != NULL) - { - Saw_named_type* q; - for (q = saw; q != NULL; q = q->next) - { - if (q->nt == nt) - { - // If this is an error, it will be reported - // elsewhere. - break; - } - } - if (q != NULL) - continue; - saw_here.next = saw; - saw_here.nt = nt; - saw = &saw_here; - } - - // Look for a reference using a NULL struct expression. If we - // find one, fill in the struct expression with a reference to - // this field. - unsigned int subdepth; - Field_reference_expression* sub = st->field_reference_depth(NULL, name, - location, - saw, - &subdepth); - - saw = hold_saw; - - if (sub == NULL) - continue; - - if (ret == NULL || subdepth < found_depth) - { - if (ret != NULL) - delete ret; - ret = sub; - found_depth = subdepth; - Expression* here = Expression::make_field_reference(struct_expr, i, - location); - if (pf->type()->points_to() != NULL) - here = Expression::make_unary(OPERATOR_MULT, here, location); - while (sub->expr() != NULL) - { - sub = sub->expr()->deref()->field_reference_expression(); - go_assert(sub != NULL); - } - sub->set_struct_expression(here); - } - else if (subdepth > found_depth) - delete sub; - else - { - // We do not handle ambiguity here--it should be handled by - // Type::bind_field_or_method. - delete sub; - found_depth = 0; - ret = NULL; - } - } - - if (ret != NULL) - *depth = found_depth + 1; - - return ret; -} - -// Return the total number of fields, including embedded fields. - -unsigned int -Struct_type::total_field_count() const -{ - if (this->fields_ == NULL) - return 0; - unsigned int ret = 0; - for (Struct_field_list::const_iterator pf = this->fields_->begin(); - pf != this->fields_->end(); - ++pf) - { - if (!pf->is_anonymous() || pf->type()->struct_type() == NULL) - ++ret; - else - ret += pf->type()->struct_type()->total_field_count(); - } - return ret; -} - -// Return whether NAME is an unexported field, for better error reporting. - -bool -Struct_type::is_unexported_local_field(Gogo* gogo, - const std::string& name) const -{ - const Struct_field_list* fields = this->fields_; - if (fields != NULL) - { - for (Struct_field_list::const_iterator pf = fields->begin(); - pf != fields->end(); - ++pf) - { - const std::string& field_name(pf->field_name()); - if (Gogo::is_hidden_name(field_name) - && name == Gogo::unpack_hidden_name(field_name) - && gogo->pack_hidden_name(name, false) != field_name) - return true; - } - } - return false; -} - -// Finalize the methods of an unnamed struct. - -void -Struct_type::finalize_methods(Gogo* gogo) -{ - if (this->all_methods_ != NULL) - return; - - // It is possible to have multiple identical structs that have - // methods. We want them to share method tables. Otherwise we will - // emit identical methods more than once, which is bad since they - // will even have the same names. - std::pair<Identical_structs::iterator, bool> ins = - Struct_type::identical_structs.insert(std::make_pair(this, this)); - if (!ins.second) - { - // An identical struct was already entered into the hash table. - // Note that finalize_methods is, fortunately, not recursive. - this->all_methods_ = ins.first->second->all_methods_; - return; - } - - Type::finalize_methods(gogo, this, this->location_, &this->all_methods_); -} - -// Return the method NAME, or NULL if there isn't one or if it is -// ambiguous. Set *IS_AMBIGUOUS if the method exists but is -// ambiguous. - -Method* -Struct_type::method_function(const std::string& name, bool* is_ambiguous) const -{ - return Type::method_function(this->all_methods_, name, is_ambiguous); -} - -// Return a pointer to the interface method table for this type for -// the interface INTERFACE. IS_POINTER is true if this is for a -// pointer to THIS. - -tree -Struct_type::interface_method_table(Gogo* gogo, - const Interface_type* interface, - bool is_pointer) -{ - return Type::interface_method_table(gogo, this, interface, is_pointer, - &this->interface_method_tables_, - &this->pointer_interface_method_tables_); -} - -// Convert struct fields to the backend representation. This is not -// declared in types.h so that types.h doesn't have to #include -// backend.h. - -static void -get_backend_struct_fields(Gogo* gogo, const Struct_field_list* fields, - bool use_placeholder, - std::vector<Backend::Btyped_identifier>* bfields) -{ - bfields->resize(fields->size()); - size_t i = 0; - for (Struct_field_list::const_iterator p = fields->begin(); - p != fields->end(); - ++p, ++i) - { - (*bfields)[i].name = Gogo::unpack_hidden_name(p->field_name()); - (*bfields)[i].btype = (use_placeholder - ? p->type()->get_backend_placeholder(gogo) - : p->type()->get_backend(gogo)); - (*bfields)[i].location = p->location(); - } - go_assert(i == fields->size()); -} - -// Get the tree for a struct type. - -Btype* -Struct_type::do_get_backend(Gogo* gogo) -{ - std::vector<Backend::Btyped_identifier> bfields; - get_backend_struct_fields(gogo, this->fields_, false, &bfields); - return gogo->backend()->struct_type(bfields); -} - -// Finish the backend representation of the fields of a struct. - -void -Struct_type::finish_backend_fields(Gogo* gogo) -{ - const Struct_field_list* fields = this->fields_; - if (fields != NULL) - { - for (Struct_field_list::const_iterator p = fields->begin(); - p != fields->end(); - ++p) - p->type()->get_backend(gogo); - } -} - -// The type of a struct type descriptor. - -Type* -Struct_type::make_struct_type_descriptor_type() -{ - static Type* ret; - if (ret == NULL) - { - Type* tdt = Type::make_type_descriptor_type(); - Type* ptdt = Type::make_type_descriptor_ptr_type(); - - Type* uintptr_type = Type::lookup_integer_type("uintptr"); - Type* string_type = Type::lookup_string_type(); - Type* pointer_string_type = Type::make_pointer_type(string_type); - - Struct_type* sf = - Type::make_builtin_struct_type(5, - "name", pointer_string_type, - "pkgPath", pointer_string_type, - "typ", ptdt, - "tag", pointer_string_type, - "offset", uintptr_type); - Type* nsf = Type::make_builtin_named_type("structField", sf); - - Type* slice_type = Type::make_array_type(nsf, NULL); - - Struct_type* s = Type::make_builtin_struct_type(2, - "", tdt, - "fields", slice_type); - - ret = Type::make_builtin_named_type("StructType", s); - } - - return ret; -} - -// Build a type descriptor for a struct type. - -Expression* -Struct_type::do_type_descriptor(Gogo* gogo, Named_type* name) -{ - Location bloc = Linemap::predeclared_location(); - - Type* stdt = Struct_type::make_struct_type_descriptor_type(); - - const Struct_field_list* fields = stdt->struct_type()->fields(); - - Expression_list* vals = new Expression_list(); - vals->reserve(2); - - const Methods* methods = this->methods(); - // A named struct should not have methods--the methods should attach - // to the named type. - go_assert(methods == NULL || name == NULL); - - Struct_field_list::const_iterator ps = fields->begin(); - go_assert(ps->is_field_name("commonType")); - vals->push_back(this->type_descriptor_constructor(gogo, - RUNTIME_TYPE_KIND_STRUCT, - name, methods, true)); - - ++ps; - go_assert(ps->is_field_name("fields")); - - Expression_list* elements = new Expression_list(); - elements->reserve(this->fields_->size()); - Type* element_type = ps->type()->array_type()->element_type(); - for (Struct_field_list::const_iterator pf = this->fields_->begin(); - pf != this->fields_->end(); - ++pf) - { - const Struct_field_list* f = element_type->struct_type()->fields(); - - Expression_list* fvals = new Expression_list(); - fvals->reserve(5); - - Struct_field_list::const_iterator q = f->begin(); - go_assert(q->is_field_name("name")); - if (pf->is_anonymous()) - fvals->push_back(Expression::make_nil(bloc)); - else - { - std::string n = Gogo::unpack_hidden_name(pf->field_name()); - Expression* s = Expression::make_string(n, bloc); - fvals->push_back(Expression::make_unary(OPERATOR_AND, s, bloc)); - } - - ++q; - go_assert(q->is_field_name("pkgPath")); - if (!Gogo::is_hidden_name(pf->field_name())) - fvals->push_back(Expression::make_nil(bloc)); - else - { - std::string n = Gogo::hidden_name_pkgpath(pf->field_name()); - Expression* s = Expression::make_string(n, bloc); - fvals->push_back(Expression::make_unary(OPERATOR_AND, s, bloc)); - } - - ++q; - go_assert(q->is_field_name("typ")); - fvals->push_back(Expression::make_type_descriptor(pf->type(), bloc)); - - ++q; - go_assert(q->is_field_name("tag")); - if (!pf->has_tag()) - fvals->push_back(Expression::make_nil(bloc)); - else - { - Expression* s = Expression::make_string(pf->tag(), bloc); - fvals->push_back(Expression::make_unary(OPERATOR_AND, s, bloc)); - } - - ++q; - go_assert(q->is_field_name("offset")); - fvals->push_back(Expression::make_struct_field_offset(this, &*pf)); - - Expression* v = Expression::make_struct_composite_literal(element_type, - fvals, bloc); - elements->push_back(v); - } - - vals->push_back(Expression::make_slice_composite_literal(ps->type(), - elements, bloc)); - - return Expression::make_struct_composite_literal(stdt, vals, bloc); -} - -// Write the hash function for a struct which can not use the identity -// function. - -void -Struct_type::write_hash_function(Gogo* gogo, Named_type*, - Function_type* hash_fntype, - Function_type* equal_fntype) -{ - Location bloc = Linemap::predeclared_location(); - - // The pointer to the struct that we are going to hash. This is an - // argument to the hash function we are implementing here. - Named_object* key_arg = gogo->lookup("key", NULL); - go_assert(key_arg != NULL); - Type* key_arg_type = key_arg->var_value()->type(); - - Type* uintptr_type = Type::lookup_integer_type("uintptr"); - - // Get a 0. - mpz_t ival; - mpz_init_set_ui(ival, 0); - Expression* zero = Expression::make_integer(&ival, uintptr_type, bloc); - mpz_clear(ival); - - // Make a temporary to hold the return value, initialized to 0. - Temporary_statement* retval = Statement::make_temporary(uintptr_type, zero, - bloc); - gogo->add_statement(retval); - - // Make a temporary to hold the key as a uintptr. - Expression* ref = Expression::make_var_reference(key_arg, bloc); - ref = Expression::make_cast(uintptr_type, ref, bloc); - Temporary_statement* key = Statement::make_temporary(uintptr_type, ref, - bloc); - gogo->add_statement(key); - - // Loop over the struct fields. - bool first = true; - const Struct_field_list* fields = this->fields_; - for (Struct_field_list::const_iterator pf = fields->begin(); - pf != fields->end(); - ++pf) - { - if (Gogo::is_sink_name(pf->field_name())) - continue; - - if (first) - first = false; - else - { - // Multiply retval by 33. - mpz_init_set_ui(ival, 33); - Expression* i33 = Expression::make_integer(&ival, uintptr_type, - bloc); - mpz_clear(ival); - - ref = Expression::make_temporary_reference(retval, bloc); - Statement* s = Statement::make_assignment_operation(OPERATOR_MULTEQ, - ref, i33, bloc); - gogo->add_statement(s); - } - - // Get a pointer to the value of this field. - Expression* offset = Expression::make_struct_field_offset(this, &*pf); - ref = Expression::make_temporary_reference(key, bloc); - Expression* subkey = Expression::make_binary(OPERATOR_PLUS, ref, offset, - bloc); - subkey = Expression::make_cast(key_arg_type, subkey, bloc); - - // Get the size of this field. - Expression* size = Expression::make_type_info(pf->type(), - Expression::TYPE_INFO_SIZE); - - // Get the hash function to use for the type of this field. - Named_object* hash_fn; - Named_object* equal_fn; - pf->type()->type_functions(gogo, pf->type()->named_type(), hash_fntype, - equal_fntype, &hash_fn, &equal_fn); - - // Call the hash function for the field. - Expression_list* args = new Expression_list(); - args->push_back(subkey); - args->push_back(size); - Expression* func = Expression::make_func_reference(hash_fn, NULL, bloc); - Expression* call = Expression::make_call(func, args, false, bloc); - - // Add the field's hash value to retval. - Temporary_reference_expression* tref = - Expression::make_temporary_reference(retval, bloc); - tref->set_is_lvalue(); - Statement* s = Statement::make_assignment_operation(OPERATOR_PLUSEQ, - tref, call, bloc); - gogo->add_statement(s); - } - - // Return retval to the caller of the hash function. - Expression_list* vals = new Expression_list(); - ref = Expression::make_temporary_reference(retval, bloc); - vals->push_back(ref); - Statement* s = Statement::make_return_statement(vals, bloc); - gogo->add_statement(s); -} - -// Write the equality function for a struct which can not use the -// identity function. - -void -Struct_type::write_equal_function(Gogo* gogo, Named_type* name) -{ - Location bloc = Linemap::predeclared_location(); - - // The pointers to the structs we are going to compare. - Named_object* key1_arg = gogo->lookup("key1", NULL); - Named_object* key2_arg = gogo->lookup("key2", NULL); - go_assert(key1_arg != NULL && key2_arg != NULL); - - // Build temporaries with the right types. - Type* pt = Type::make_pointer_type(name != NULL - ? static_cast<Type*>(name) - : static_cast<Type*>(this)); - - Expression* ref = Expression::make_var_reference(key1_arg, bloc); - ref = Expression::make_unsafe_cast(pt, ref, bloc); - Temporary_statement* p1 = Statement::make_temporary(pt, ref, bloc); - gogo->add_statement(p1); - - ref = Expression::make_var_reference(key2_arg, bloc); - ref = Expression::make_unsafe_cast(pt, ref, bloc); - Temporary_statement* p2 = Statement::make_temporary(pt, ref, bloc); - gogo->add_statement(p2); - - const Struct_field_list* fields = this->fields_; - unsigned int field_index = 0; - for (Struct_field_list::const_iterator pf = fields->begin(); - pf != fields->end(); - ++pf, ++field_index) - { - if (Gogo::is_sink_name(pf->field_name())) - continue; - - // Compare one field in both P1 and P2. - Expression* f1 = Expression::make_temporary_reference(p1, bloc); - f1 = Expression::make_unary(OPERATOR_MULT, f1, bloc); - f1 = Expression::make_field_reference(f1, field_index, bloc); - - Expression* f2 = Expression::make_temporary_reference(p2, bloc); - f2 = Expression::make_unary(OPERATOR_MULT, f2, bloc); - f2 = Expression::make_field_reference(f2, field_index, bloc); - - Expression* cond = Expression::make_binary(OPERATOR_NOTEQ, f1, f2, bloc); - - // If the values are not equal, return false. - gogo->start_block(bloc); - Expression_list* vals = new Expression_list(); - vals->push_back(Expression::make_boolean(false, bloc)); - Statement* s = Statement::make_return_statement(vals, bloc); - gogo->add_statement(s); - Block* then_block = gogo->finish_block(bloc); - - s = Statement::make_if_statement(cond, then_block, NULL, bloc); - gogo->add_statement(s); - } - - // All the fields are equal, so return true. - Expression_list* vals = new Expression_list(); - vals->push_back(Expression::make_boolean(true, bloc)); - Statement* s = Statement::make_return_statement(vals, bloc); - gogo->add_statement(s); -} - -// Reflection string. - -void -Struct_type::do_reflection(Gogo* gogo, std::string* ret) const -{ - ret->append("struct {"); - - for (Struct_field_list::const_iterator p = this->fields_->begin(); - p != this->fields_->end(); - ++p) - { - if (p != this->fields_->begin()) - ret->push_back(';'); - ret->push_back(' '); - if (p->is_anonymous()) - ret->push_back('?'); - else - ret->append(Gogo::unpack_hidden_name(p->field_name())); - ret->push_back(' '); - this->append_reflection(p->type(), gogo, ret); - - if (p->has_tag()) - { - const std::string& tag(p->tag()); - ret->append(" \""); - for (std::string::const_iterator p = tag.begin(); - p != tag.end(); - ++p) - { - if (*p == '\0') - ret->append("\\x00"); - else if (*p == '\n') - ret->append("\\n"); - else if (*p == '\t') - ret->append("\\t"); - else if (*p == '"') - ret->append("\\\""); - else if (*p == '\\') - ret->append("\\\\"); - else - ret->push_back(*p); - } - ret->push_back('"'); - } - } - - if (!this->fields_->empty()) - ret->push_back(' '); - - ret->push_back('}'); -} - -// Mangled name. - -void -Struct_type::do_mangled_name(Gogo* gogo, std::string* ret) const -{ - ret->push_back('S'); - - const Struct_field_list* fields = this->fields_; - if (fields != NULL) - { - for (Struct_field_list::const_iterator p = fields->begin(); - p != fields->end(); - ++p) - { - if (p->is_anonymous()) - ret->append("0_"); - else - { - std::string n = Gogo::unpack_hidden_name(p->field_name()); - char buf[20]; - snprintf(buf, sizeof buf, "%u_", - static_cast<unsigned int>(n.length())); - ret->append(buf); - ret->append(n); - } - this->append_mangled_name(p->type(), gogo, ret); - if (p->has_tag()) - { - const std::string& tag(p->tag()); - std::string out; - for (std::string::const_iterator p = tag.begin(); - p != tag.end(); - ++p) - { - if (ISALNUM(*p) || *p == '_') - out.push_back(*p); - else - { - char buf[20]; - snprintf(buf, sizeof buf, ".%x.", - static_cast<unsigned int>(*p)); - out.append(buf); - } - } - char buf[20]; - snprintf(buf, sizeof buf, "T%u_", - static_cast<unsigned int>(out.length())); - ret->append(buf); - ret->append(out); - } - } - } - - ret->push_back('e'); -} - -// If the offset of field INDEX in the backend implementation can be -// determined, set *POFFSET to the offset in bytes and return true. -// Otherwise, return false. - -bool -Struct_type::backend_field_offset(Gogo* gogo, unsigned int index, - unsigned int* poffset) -{ - if (!this->is_backend_type_size_known(gogo)) - return false; - Btype* bt = this->get_backend_placeholder(gogo); - size_t offset = gogo->backend()->type_field_offset(bt, index); - *poffset = static_cast<unsigned int>(offset); - if (*poffset != offset) - return false; - return true; -} - -// Export. - -void -Struct_type::do_export(Export* exp) const -{ - exp->write_c_string("struct { "); - const Struct_field_list* fields = this->fields_; - go_assert(fields != NULL); - for (Struct_field_list::const_iterator p = fields->begin(); - p != fields->end(); - ++p) - { - if (p->is_anonymous()) - exp->write_string("? "); - else - { - exp->write_string(p->field_name()); - exp->write_c_string(" "); - } - exp->write_type(p->type()); - - if (p->has_tag()) - { - exp->write_c_string(" "); - Expression* expr = - Expression::make_string(p->tag(), Linemap::predeclared_location()); - expr->export_expression(exp); - delete expr; - } - - exp->write_c_string("; "); - } - exp->write_c_string("}"); -} - -// Import. - -Struct_type* -Struct_type::do_import(Import* imp) -{ - imp->require_c_string("struct { "); - Struct_field_list* fields = new Struct_field_list; - if (imp->peek_char() != '}') - { - while (true) - { - std::string name; - if (imp->match_c_string("? ")) - imp->advance(2); - else - { - name = imp->read_identifier(); - imp->require_c_string(" "); - } - Type* ftype = imp->read_type(); - - Struct_field sf(Typed_identifier(name, ftype, imp->location())); - - if (imp->peek_char() == ' ') - { - imp->advance(1); - Expression* expr = Expression::import_expression(imp); - String_expression* sexpr = expr->string_expression(); - go_assert(sexpr != NULL); - sf.set_tag(sexpr->val()); - delete sexpr; - } - - imp->require_c_string("; "); - fields->push_back(sf); - if (imp->peek_char() == '}') - break; - } - } - imp->require_c_string("}"); - - return Type::make_struct_type(fields, imp->location()); -} - -// Make a struct type. - -Struct_type* -Type::make_struct_type(Struct_field_list* fields, - Location location) -{ - return new Struct_type(fields, location); -} - -// Class Array_type. - -// Whether two array types are identical. - -bool -Array_type::is_identical(const Array_type* t, bool errors_are_identical) const -{ - if (!Type::are_identical(this->element_type(), t->element_type(), - errors_are_identical, NULL)) - return false; - - Expression* l1 = this->length(); - Expression* l2 = t->length(); - - // Slices of the same element type are identical. - if (l1 == NULL && l2 == NULL) - return true; - - // Arrays of the same element type are identical if they have the - // same length. - if (l1 != NULL && l2 != NULL) - { - if (l1 == l2) - return true; - - // Try to determine the lengths. If we can't, assume the arrays - // are not identical. - bool ret = false; - Numeric_constant nc1, nc2; - if (l1->numeric_constant_value(&nc1) - && l2->numeric_constant_value(&nc2)) - { - mpz_t v1; - if (nc1.to_int(&v1)) - { - mpz_t v2; - if (nc2.to_int(&v2)) - { - ret = mpz_cmp(v1, v2) == 0; - mpz_clear(v2); - } - mpz_clear(v1); - } - } - return ret; - } - - // Otherwise the arrays are not identical. - return false; -} - -// Traversal. - -int -Array_type::do_traverse(Traverse* traverse) -{ - if (Type::traverse(this->element_type_, traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - if (this->length_ != NULL - && Expression::traverse(&this->length_, traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - return TRAVERSE_CONTINUE; -} - -// Check that the length is valid. - -bool -Array_type::verify_length() -{ - if (this->length_ == NULL) - return true; - - Type_context context(Type::lookup_integer_type("int"), false); - this->length_->determine_type(&context); - - if (!this->length_->is_constant()) - { - error_at(this->length_->location(), "array bound is not constant"); - return false; - } - - Numeric_constant nc; - if (!this->length_->numeric_constant_value(&nc)) - { - if (this->length_->type()->integer_type() != NULL - || this->length_->type()->float_type() != NULL) - error_at(this->length_->location(), "array bound is not constant"); - else - error_at(this->length_->location(), "array bound is not numeric"); - return false; - } - - unsigned long val; - switch (nc.to_unsigned_long(&val)) - { - case Numeric_constant::NC_UL_VALID: - break; - case Numeric_constant::NC_UL_NOTINT: - error_at(this->length_->location(), "array bound truncated to integer"); - return false; - case Numeric_constant::NC_UL_NEGATIVE: - error_at(this->length_->location(), "negative array bound"); - return false; - case Numeric_constant::NC_UL_BIG: - error_at(this->length_->location(), "array bound overflows"); - return false; - default: - go_unreachable(); - } - - Type* int_type = Type::lookup_integer_type("int"); - unsigned int tbits = int_type->integer_type()->bits(); - if (sizeof(val) <= tbits * 8 - && val >> (tbits - 1) != 0) - { - error_at(this->length_->location(), "array bound overflows"); - return false; - } - - return true; -} - -// Verify the type. - -bool -Array_type::do_verify() -{ - if (!this->verify_length()) - this->length_ = Expression::make_error(this->length_->location()); - return true; -} - -// Whether we can use memcmp to compare this array. - -bool -Array_type::do_compare_is_identity(Gogo* gogo) -{ - if (this->length_ == NULL) - return false; - - // Check for [...], which indicates that this is not a real type. - if (this->length_->is_nil_expression()) - return false; - - if (!this->element_type_->compare_is_identity(gogo)) - return false; - - // If there is any padding, then we can't use memcmp. - unsigned int size; - unsigned int align; - if (!this->element_type_->backend_type_size(gogo, &size) - || !this->element_type_->backend_type_align(gogo, &align)) - return false; - if ((size & (align - 1)) != 0) - return false; - - return true; -} - -// Array type hash code. - -unsigned int -Array_type::do_hash_for_method(Gogo* gogo) const -{ - // There is no very convenient way to get a hash code for the - // length. - return this->element_type_->hash_for_method(gogo) + 1; -} - -// Write the hash function for an array which can not use the identify -// function. - -void -Array_type::write_hash_function(Gogo* gogo, Named_type* name, - Function_type* hash_fntype, - Function_type* equal_fntype) -{ - Location bloc = Linemap::predeclared_location(); - - // The pointer to the array that we are going to hash. This is an - // argument to the hash function we are implementing here. - Named_object* key_arg = gogo->lookup("key", NULL); - go_assert(key_arg != NULL); - Type* key_arg_type = key_arg->var_value()->type(); - - Type* uintptr_type = Type::lookup_integer_type("uintptr"); - - // Get a 0. - mpz_t ival; - mpz_init_set_ui(ival, 0); - Expression* zero = Expression::make_integer(&ival, uintptr_type, bloc); - mpz_clear(ival); - - // Make a temporary to hold the return value, initialized to 0. - Temporary_statement* retval = Statement::make_temporary(uintptr_type, zero, - bloc); - gogo->add_statement(retval); - - // Make a temporary to hold the key as a uintptr. - Expression* ref = Expression::make_var_reference(key_arg, bloc); - ref = Expression::make_cast(uintptr_type, ref, bloc); - Temporary_statement* key = Statement::make_temporary(uintptr_type, ref, - bloc); - gogo->add_statement(key); - - // Loop over the array elements. - // for i = range a - Type* int_type = Type::lookup_integer_type("int"); - Temporary_statement* index = Statement::make_temporary(int_type, NULL, bloc); - gogo->add_statement(index); - - Expression* iref = Expression::make_temporary_reference(index, bloc); - Expression* aref = Expression::make_var_reference(key_arg, bloc); - Type* pt = Type::make_pointer_type(name != NULL - ? static_cast<Type*>(name) - : static_cast<Type*>(this)); - aref = Expression::make_cast(pt, aref, bloc); - For_range_statement* for_range = Statement::make_for_range_statement(iref, - NULL, - aref, - bloc); - - gogo->start_block(bloc); - - // Multiply retval by 33. - mpz_init_set_ui(ival, 33); - Expression* i33 = Expression::make_integer(&ival, uintptr_type, bloc); - mpz_clear(ival); - - ref = Expression::make_temporary_reference(retval, bloc); - Statement* s = Statement::make_assignment_operation(OPERATOR_MULTEQ, ref, - i33, bloc); - gogo->add_statement(s); - - // Get the hash function for the element type. - Named_object* hash_fn; - Named_object* equal_fn; - this->element_type_->type_functions(gogo, this->element_type_->named_type(), - hash_fntype, equal_fntype, &hash_fn, - &equal_fn); - - // Get a pointer to this element in the loop. - Expression* subkey = Expression::make_temporary_reference(key, bloc); - subkey = Expression::make_cast(key_arg_type, subkey, bloc); - - // Get the size of each element. - Expression* ele_size = Expression::make_type_info(this->element_type_, - Expression::TYPE_INFO_SIZE); - - // Get the hash of this element. - Expression_list* args = new Expression_list(); - args->push_back(subkey); - args->push_back(ele_size); - Expression* func = Expression::make_func_reference(hash_fn, NULL, bloc); - Expression* call = Expression::make_call(func, args, false, bloc); - - // Add the element's hash value to retval. - Temporary_reference_expression* tref = - Expression::make_temporary_reference(retval, bloc); - tref->set_is_lvalue(); - s = Statement::make_assignment_operation(OPERATOR_PLUSEQ, tref, call, bloc); - gogo->add_statement(s); - - // Increase the element pointer. - tref = Expression::make_temporary_reference(key, bloc); - tref->set_is_lvalue(); - s = Statement::make_assignment_operation(OPERATOR_PLUSEQ, tref, ele_size, - bloc); - - Block* statements = gogo->finish_block(bloc); - - for_range->add_statements(statements); - gogo->add_statement(for_range); - - // Return retval to the caller of the hash function. - Expression_list* vals = new Expression_list(); - ref = Expression::make_temporary_reference(retval, bloc); - vals->push_back(ref); - s = Statement::make_return_statement(vals, bloc); - gogo->add_statement(s); -} - -// Write the equality function for an array which can not use the -// identity function. - -void -Array_type::write_equal_function(Gogo* gogo, Named_type* name) -{ - Location bloc = Linemap::predeclared_location(); - - // The pointers to the arrays we are going to compare. - Named_object* key1_arg = gogo->lookup("key1", NULL); - Named_object* key2_arg = gogo->lookup("key2", NULL); - go_assert(key1_arg != NULL && key2_arg != NULL); - - // Build temporaries for the keys with the right types. - Type* pt = Type::make_pointer_type(name != NULL - ? static_cast<Type*>(name) - : static_cast<Type*>(this)); - - Expression* ref = Expression::make_var_reference(key1_arg, bloc); - ref = Expression::make_unsafe_cast(pt, ref, bloc); - Temporary_statement* p1 = Statement::make_temporary(pt, ref, bloc); - gogo->add_statement(p1); - - ref = Expression::make_var_reference(key2_arg, bloc); - ref = Expression::make_unsafe_cast(pt, ref, bloc); - Temporary_statement* p2 = Statement::make_temporary(pt, ref, bloc); - gogo->add_statement(p2); - - // Loop over the array elements. - // for i = range a - Type* int_type = Type::lookup_integer_type("int"); - Temporary_statement* index = Statement::make_temporary(int_type, NULL, bloc); - gogo->add_statement(index); - - Expression* iref = Expression::make_temporary_reference(index, bloc); - Expression* aref = Expression::make_temporary_reference(p1, bloc); - For_range_statement* for_range = Statement::make_for_range_statement(iref, - NULL, - aref, - bloc); - - gogo->start_block(bloc); - - // Compare element in P1 and P2. - Expression* e1 = Expression::make_temporary_reference(p1, bloc); - e1 = Expression::make_unary(OPERATOR_MULT, e1, bloc); - ref = Expression::make_temporary_reference(index, bloc); - e1 = Expression::make_array_index(e1, ref, NULL, bloc); - - Expression* e2 = Expression::make_temporary_reference(p2, bloc); - e2 = Expression::make_unary(OPERATOR_MULT, e2, bloc); - ref = Expression::make_temporary_reference(index, bloc); - e2 = Expression::make_array_index(e2, ref, NULL, bloc); - - Expression* cond = Expression::make_binary(OPERATOR_NOTEQ, e1, e2, bloc); - - // If the elements are not equal, return false. - gogo->start_block(bloc); - Expression_list* vals = new Expression_list(); - vals->push_back(Expression::make_boolean(false, bloc)); - Statement* s = Statement::make_return_statement(vals, bloc); - gogo->add_statement(s); - Block* then_block = gogo->finish_block(bloc); - - s = Statement::make_if_statement(cond, then_block, NULL, bloc); - gogo->add_statement(s); - - Block* statements = gogo->finish_block(bloc); - - for_range->add_statements(statements); - gogo->add_statement(for_range); - - // All the elements are equal, so return true. - vals = new Expression_list(); - vals->push_back(Expression::make_boolean(true, bloc)); - s = Statement::make_return_statement(vals, bloc); - gogo->add_statement(s); -} - -// Get a tree for the length of a fixed array. The length may be -// computed using a function call, so we must only evaluate it once. - -tree -Array_type::get_length_tree(Gogo* gogo) -{ - go_assert(this->length_ != NULL); - if (this->length_tree_ == NULL_TREE) - { - Numeric_constant nc; - mpz_t val; - if (this->length_->numeric_constant_value(&nc) && nc.to_int(&val)) - { - if (mpz_sgn(val) < 0) - { - this->length_tree_ = error_mark_node; - return this->length_tree_; - } - Type* t = nc.type(); - if (t == NULL) - t = Type::lookup_integer_type("int"); - else if (t->is_abstract()) - t = t->make_non_abstract_type(); - tree tt = type_to_tree(t->get_backend(gogo)); - this->length_tree_ = Expression::integer_constant_tree(val, tt); - mpz_clear(val); - } - else - { - // Make up a translation context for the array length - // expression. FIXME: This won't work in general. - Translate_context context(gogo, NULL, NULL, NULL); - tree len = this->length_->get_tree(&context); - if (len != error_mark_node) - { - Type* int_type = Type::lookup_integer_type("int"); - tree int_type_tree = type_to_tree(int_type->get_backend(gogo)); - len = convert_to_integer(int_type_tree, len); - len = save_expr(len); - } - this->length_tree_ = len; - } - } - return this->length_tree_; -} - -// Get the backend representation of the fields of a slice. This is -// not declared in types.h so that types.h doesn't have to #include -// backend.h. -// -// We use int for the count and capacity fields. This matches 6g. -// The language more or less assumes that we can't allocate space of a -// size which does not fit in int. - -static void -get_backend_slice_fields(Gogo* gogo, Array_type* type, bool use_placeholder, - std::vector<Backend::Btyped_identifier>* bfields) -{ - bfields->resize(3); - - Type* pet = Type::make_pointer_type(type->element_type()); - Btype* pbet = (use_placeholder - ? pet->get_backend_placeholder(gogo) - : pet->get_backend(gogo)); - Location ploc = Linemap::predeclared_location(); - - Backend::Btyped_identifier* p = &(*bfields)[0]; - p->name = "__values"; - p->btype = pbet; - p->location = ploc; - - Type* int_type = Type::lookup_integer_type("int"); - - p = &(*bfields)[1]; - p->name = "__count"; - p->btype = int_type->get_backend(gogo); - p->location = ploc; - - p = &(*bfields)[2]; - p->name = "__capacity"; - p->btype = int_type->get_backend(gogo); - p->location = ploc; -} - -// Get a tree for the type of this array. A fixed array is simply -// represented as ARRAY_TYPE with the appropriate index--i.e., it is -// just like an array in C. An open array is a struct with three -// fields: a data pointer, the length, and the capacity. - -Btype* -Array_type::do_get_backend(Gogo* gogo) -{ - if (this->length_ == NULL) - { - std::vector<Backend::Btyped_identifier> bfields; - get_backend_slice_fields(gogo, this, false, &bfields); - return gogo->backend()->struct_type(bfields); - } - else - { - Btype* element = this->get_backend_element(gogo, false); - Bexpression* len = this->get_backend_length(gogo); - return gogo->backend()->array_type(element, len); - } -} - -// Return the backend representation of the element type. - -Btype* -Array_type::get_backend_element(Gogo* gogo, bool use_placeholder) -{ - if (use_placeholder) - return this->element_type_->get_backend_placeholder(gogo); - else - return this->element_type_->get_backend(gogo); -} - -// Return the backend representation of the length. - -Bexpression* -Array_type::get_backend_length(Gogo* gogo) -{ - return tree_to_expr(this->get_length_tree(gogo)); -} - -// Finish backend representation of the array. - -void -Array_type::finish_backend_element(Gogo* gogo) -{ - Type* et = this->array_type()->element_type(); - et->get_backend(gogo); - if (this->is_slice_type()) - { - // This relies on the fact that we always use the same - // structure for a pointer to any given type. - Type* pet = Type::make_pointer_type(et); - pet->get_backend(gogo); - } -} - -// Return a tree for a pointer to the values in ARRAY. - -tree -Array_type::value_pointer_tree(Gogo*, tree array) const -{ - tree ret; - if (this->length() != NULL) - { - // Fixed array. - ret = fold_convert(build_pointer_type(TREE_TYPE(TREE_TYPE(array))), - build_fold_addr_expr(array)); - } - else - { - // Open array. - tree field = TYPE_FIELDS(TREE_TYPE(array)); - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), - "__values") == 0); - ret = fold_build3(COMPONENT_REF, TREE_TYPE(field), array, field, - NULL_TREE); - } - if (TREE_CONSTANT(array)) - TREE_CONSTANT(ret) = 1; - return ret; -} - -// Return a tree for the length of the array ARRAY which has this -// type. - -tree -Array_type::length_tree(Gogo* gogo, tree array) -{ - if (this->length_ != NULL) - { - if (TREE_CODE(array) == SAVE_EXPR) - return this->get_length_tree(gogo); - else - { - tree len = this->get_length_tree(gogo); - return omit_one_operand(TREE_TYPE(len), len, array); - } - } - - // This is an open array. We need to read the length field. - - tree type = TREE_TYPE(array); - go_assert(TREE_CODE(type) == RECORD_TYPE); - - tree field = DECL_CHAIN(TYPE_FIELDS(type)); - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__count") == 0); - - tree ret = build3(COMPONENT_REF, TREE_TYPE(field), array, field, NULL_TREE); - if (TREE_CONSTANT(array)) - TREE_CONSTANT(ret) = 1; - return ret; -} - -// Return a tree for the capacity of the array ARRAY which has this -// type. - -tree -Array_type::capacity_tree(Gogo* gogo, tree array) -{ - if (this->length_ != NULL) - { - tree len = this->get_length_tree(gogo); - return omit_one_operand(TREE_TYPE(len), len, array); - } - - // This is an open array. We need to read the capacity field. - - tree type = TREE_TYPE(array); - go_assert(TREE_CODE(type) == RECORD_TYPE); - - tree field = DECL_CHAIN(DECL_CHAIN(TYPE_FIELDS(type))); - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__capacity") == 0); - - return build3(COMPONENT_REF, TREE_TYPE(field), array, field, NULL_TREE); -} - -// Export. - -void -Array_type::do_export(Export* exp) const -{ - exp->write_c_string("["); - if (this->length_ != NULL) - this->length_->export_expression(exp); - exp->write_c_string("] "); - exp->write_type(this->element_type_); -} - -// Import. - -Array_type* -Array_type::do_import(Import* imp) -{ - imp->require_c_string("["); - Expression* length; - if (imp->peek_char() == ']') - length = NULL; - else - length = Expression::import_expression(imp); - imp->require_c_string("] "); - Type* element_type = imp->read_type(); - return Type::make_array_type(element_type, length); -} - -// The type of an array type descriptor. - -Type* -Array_type::make_array_type_descriptor_type() -{ - static Type* ret; - if (ret == NULL) - { - Type* tdt = Type::make_type_descriptor_type(); - Type* ptdt = Type::make_type_descriptor_ptr_type(); - - Type* uintptr_type = Type::lookup_integer_type("uintptr"); - - Struct_type* sf = - Type::make_builtin_struct_type(4, - "", tdt, - "elem", ptdt, - "slice", ptdt, - "len", uintptr_type); - - ret = Type::make_builtin_named_type("ArrayType", sf); - } - - return ret; -} - -// The type of an slice type descriptor. - -Type* -Array_type::make_slice_type_descriptor_type() -{ - static Type* ret; - if (ret == NULL) - { - Type* tdt = Type::make_type_descriptor_type(); - Type* ptdt = Type::make_type_descriptor_ptr_type(); - - Struct_type* sf = - Type::make_builtin_struct_type(2, - "", tdt, - "elem", ptdt); - - ret = Type::make_builtin_named_type("SliceType", sf); - } - - return ret; -} - -// Build a type descriptor for an array/slice type. - -Expression* -Array_type::do_type_descriptor(Gogo* gogo, Named_type* name) -{ - if (this->length_ != NULL) - return this->array_type_descriptor(gogo, name); - else - return this->slice_type_descriptor(gogo, name); -} - -// Build a type descriptor for an array type. - -Expression* -Array_type::array_type_descriptor(Gogo* gogo, Named_type* name) -{ - Location bloc = Linemap::predeclared_location(); - - Type* atdt = Array_type::make_array_type_descriptor_type(); - - const Struct_field_list* fields = atdt->struct_type()->fields(); - - Expression_list* vals = new Expression_list(); - vals->reserve(3); - - Struct_field_list::const_iterator p = fields->begin(); - go_assert(p->is_field_name("commonType")); - vals->push_back(this->type_descriptor_constructor(gogo, - RUNTIME_TYPE_KIND_ARRAY, - name, NULL, true)); - - ++p; - go_assert(p->is_field_name("elem")); - vals->push_back(Expression::make_type_descriptor(this->element_type_, bloc)); - - ++p; - go_assert(p->is_field_name("slice")); - Type* slice_type = Type::make_array_type(this->element_type_, NULL); - vals->push_back(Expression::make_type_descriptor(slice_type, bloc)); - - ++p; - go_assert(p->is_field_name("len")); - vals->push_back(Expression::make_cast(p->type(), this->length_, bloc)); - - ++p; - go_assert(p == fields->end()); - - return Expression::make_struct_composite_literal(atdt, vals, bloc); -} - -// Build a type descriptor for a slice type. - -Expression* -Array_type::slice_type_descriptor(Gogo* gogo, Named_type* name) -{ - Location bloc = Linemap::predeclared_location(); - - Type* stdt = Array_type::make_slice_type_descriptor_type(); - - const Struct_field_list* fields = stdt->struct_type()->fields(); - - Expression_list* vals = new Expression_list(); - vals->reserve(2); - - Struct_field_list::const_iterator p = fields->begin(); - go_assert(p->is_field_name("commonType")); - vals->push_back(this->type_descriptor_constructor(gogo, - RUNTIME_TYPE_KIND_SLICE, - name, NULL, true)); - - ++p; - go_assert(p->is_field_name("elem")); - vals->push_back(Expression::make_type_descriptor(this->element_type_, bloc)); - - ++p; - go_assert(p == fields->end()); - - return Expression::make_struct_composite_literal(stdt, vals, bloc); -} - -// Reflection string. - -void -Array_type::do_reflection(Gogo* gogo, std::string* ret) const -{ - ret->push_back('['); - if (this->length_ != NULL) - { - Numeric_constant nc; - unsigned long val; - if (!this->length_->numeric_constant_value(&nc) - || nc.to_unsigned_long(&val) != Numeric_constant::NC_UL_VALID) - error_at(this->length_->location(), "invalid array length"); - else - { - char buf[50]; - snprintf(buf, sizeof buf, "%lu", val); - ret->append(buf); - } - } - ret->push_back(']'); - - this->append_reflection(this->element_type_, gogo, ret); -} - -// Mangled name. - -void -Array_type::do_mangled_name(Gogo* gogo, std::string* ret) const -{ - ret->push_back('A'); - this->append_mangled_name(this->element_type_, gogo, ret); - if (this->length_ != NULL) - { - Numeric_constant nc; - unsigned long val; - if (!this->length_->numeric_constant_value(&nc) - || nc.to_unsigned_long(&val) != Numeric_constant::NC_UL_VALID) - error_at(this->length_->location(), "invalid array length"); - else - { - char buf[50]; - snprintf(buf, sizeof buf, "%lu", val); - ret->append(buf); - } - } - ret->push_back('e'); -} - -// Make an array type. - -Array_type* -Type::make_array_type(Type* element_type, Expression* length) -{ - return new Array_type(element_type, length); -} - -// Class Map_type. - -// Traversal. - -int -Map_type::do_traverse(Traverse* traverse) -{ - if (Type::traverse(this->key_type_, traverse) == TRAVERSE_EXIT - || Type::traverse(this->val_type_, traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - return TRAVERSE_CONTINUE; -} - -// Check that the map type is OK. - -bool -Map_type::do_verify() -{ - // The runtime support uses "map[void]void". - if (!this->key_type_->is_comparable() && !this->key_type_->is_void_type()) - error_at(this->location_, "invalid map key type"); - return true; -} - -// Whether two map types are identical. - -bool -Map_type::is_identical(const Map_type* t, bool errors_are_identical) const -{ - return (Type::are_identical(this->key_type(), t->key_type(), - errors_are_identical, NULL) - && Type::are_identical(this->val_type(), t->val_type(), - errors_are_identical, NULL)); -} - -// Hash code. - -unsigned int -Map_type::do_hash_for_method(Gogo* gogo) const -{ - return (this->key_type_->hash_for_method(gogo) - + this->val_type_->hash_for_method(gogo) - + 2); -} - -// Get the backend representation for a map type. A map type is -// represented as a pointer to a struct. The struct is __go_map in -// libgo/map.h. - -Btype* -Map_type::do_get_backend(Gogo* gogo) -{ - static Btype* backend_map_type; - if (backend_map_type == NULL) - { - std::vector<Backend::Btyped_identifier> bfields(4); - - Location bloc = Linemap::predeclared_location(); - - Type* pdt = Type::make_type_descriptor_ptr_type(); - bfields[0].name = "__descriptor"; - bfields[0].btype = pdt->get_backend(gogo); - bfields[0].location = bloc; - - Type* uintptr_type = Type::lookup_integer_type("uintptr"); - bfields[1].name = "__element_count"; - bfields[1].btype = uintptr_type->get_backend(gogo); - bfields[1].location = bloc; - - bfields[2].name = "__bucket_count"; - bfields[2].btype = bfields[1].btype; - bfields[2].location = bloc; - - Btype* bvt = gogo->backend()->void_type(); - Btype* bpvt = gogo->backend()->pointer_type(bvt); - Btype* bppvt = gogo->backend()->pointer_type(bpvt); - bfields[3].name = "__buckets"; - bfields[3].btype = bppvt; - bfields[3].location = bloc; - - Btype *bt = gogo->backend()->struct_type(bfields); - bt = gogo->backend()->named_type("__go_map", bt, bloc); - backend_map_type = gogo->backend()->pointer_type(bt); - } - return backend_map_type; -} - -// The type of a map type descriptor. - -Type* -Map_type::make_map_type_descriptor_type() -{ - static Type* ret; - if (ret == NULL) - { - Type* tdt = Type::make_type_descriptor_type(); - Type* ptdt = Type::make_type_descriptor_ptr_type(); - - Struct_type* sf = - Type::make_builtin_struct_type(3, - "", tdt, - "key", ptdt, - "elem", ptdt); - - ret = Type::make_builtin_named_type("MapType", sf); - } - - return ret; -} - -// Build a type descriptor for a map type. - -Expression* -Map_type::do_type_descriptor(Gogo* gogo, Named_type* name) -{ - Location bloc = Linemap::predeclared_location(); - - Type* mtdt = Map_type::make_map_type_descriptor_type(); - - const Struct_field_list* fields = mtdt->struct_type()->fields(); - - Expression_list* vals = new Expression_list(); - vals->reserve(3); - - Struct_field_list::const_iterator p = fields->begin(); - go_assert(p->is_field_name("commonType")); - vals->push_back(this->type_descriptor_constructor(gogo, - RUNTIME_TYPE_KIND_MAP, - name, NULL, true)); - - ++p; - go_assert(p->is_field_name("key")); - vals->push_back(Expression::make_type_descriptor(this->key_type_, bloc)); - - ++p; - go_assert(p->is_field_name("elem")); - vals->push_back(Expression::make_type_descriptor(this->val_type_, bloc)); - - ++p; - go_assert(p == fields->end()); - - return Expression::make_struct_composite_literal(mtdt, vals, bloc); -} - -// A mapping from map types to map descriptors. - -Map_type::Map_descriptors Map_type::map_descriptors; - -// Build a map descriptor for this type. Return a pointer to it. - -tree -Map_type::map_descriptor_pointer(Gogo* gogo, Location location) -{ - Bvariable* bvar = this->map_descriptor(gogo); - tree var_tree = var_to_tree(bvar); - if (var_tree == error_mark_node) - return error_mark_node; - return build_fold_addr_expr_loc(location.gcc_location(), var_tree); -} - -// Build a map descriptor for this type. - -Bvariable* -Map_type::map_descriptor(Gogo* gogo) -{ - std::pair<Map_type*, Bvariable*> val(this, NULL); - std::pair<Map_type::Map_descriptors::iterator, bool> ins = - Map_type::map_descriptors.insert(val); - if (!ins.second) - return ins.first->second; - - Type* key_type = this->key_type_; - Type* val_type = this->val_type_; - - // The map entry type is a struct with three fields. Build that - // struct so that we can get the offsets of the key and value within - // a map entry. The first field should technically be a pointer to - // this type itself, but since we only care about field offsets we - // just use pointer to bool. - Type* pbool = Type::make_pointer_type(Type::make_boolean_type()); - Struct_type* map_entry_type = - Type::make_builtin_struct_type(3, - "__next", pbool, - "__key", key_type, - "__val", val_type); - - Type* map_descriptor_type = Map_type::make_map_descriptor_type(); - - const Struct_field_list* fields = - map_descriptor_type->struct_type()->fields(); - - Expression_list* vals = new Expression_list(); - vals->reserve(4); - - Location bloc = Linemap::predeclared_location(); - - Struct_field_list::const_iterator p = fields->begin(); - - go_assert(p->is_field_name("__map_descriptor")); - vals->push_back(Expression::make_type_descriptor(this, bloc)); - - ++p; - go_assert(p->is_field_name("__entry_size")); - Expression::Type_info type_info = Expression::TYPE_INFO_SIZE; - vals->push_back(Expression::make_type_info(map_entry_type, type_info)); - - Struct_field_list::const_iterator pf = map_entry_type->fields()->begin(); - ++pf; - go_assert(pf->is_field_name("__key")); - - ++p; - go_assert(p->is_field_name("__key_offset")); - vals->push_back(Expression::make_struct_field_offset(map_entry_type, &*pf)); - - ++pf; - go_assert(pf->is_field_name("__val")); - - ++p; - go_assert(p->is_field_name("__val_offset")); - vals->push_back(Expression::make_struct_field_offset(map_entry_type, &*pf)); - - ++p; - go_assert(p == fields->end()); - - Expression* initializer = - Expression::make_struct_composite_literal(map_descriptor_type, vals, bloc); - - std::string mangled_name = "__go_map_" + this->mangled_name(gogo); - Btype* map_descriptor_btype = map_descriptor_type->get_backend(gogo); - Bvariable* bvar = gogo->backend()->immutable_struct(mangled_name, true, - map_descriptor_btype, - bloc); - - Translate_context context(gogo, NULL, NULL, NULL); - context.set_is_const(); - Bexpression* binitializer = tree_to_expr(initializer->get_tree(&context)); - - gogo->backend()->immutable_struct_set_init(bvar, mangled_name, true, - map_descriptor_btype, bloc, - binitializer); - - ins.first->second = bvar; - return bvar; -} - -// Build the type of a map descriptor. This must match the struct -// __go_map_descriptor in libgo/runtime/map.h. - -Type* -Map_type::make_map_descriptor_type() -{ - static Type* ret; - if (ret == NULL) - { - Type* ptdt = Type::make_type_descriptor_ptr_type(); - Type* uintptr_type = Type::lookup_integer_type("uintptr"); - Struct_type* sf = - Type::make_builtin_struct_type(4, - "__map_descriptor", ptdt, - "__entry_size", uintptr_type, - "__key_offset", uintptr_type, - "__val_offset", uintptr_type); - ret = Type::make_builtin_named_type("__go_map_descriptor", sf); - } - return ret; -} - -// Reflection string for a map. - -void -Map_type::do_reflection(Gogo* gogo, std::string* ret) const -{ - ret->append("map["); - this->append_reflection(this->key_type_, gogo, ret); - ret->append("]"); - this->append_reflection(this->val_type_, gogo, ret); -} - -// Mangled name for a map. - -void -Map_type::do_mangled_name(Gogo* gogo, std::string* ret) const -{ - ret->push_back('M'); - this->append_mangled_name(this->key_type_, gogo, ret); - ret->append("__"); - this->append_mangled_name(this->val_type_, gogo, ret); -} - -// Export a map type. - -void -Map_type::do_export(Export* exp) const -{ - exp->write_c_string("map ["); - exp->write_type(this->key_type_); - exp->write_c_string("] "); - exp->write_type(this->val_type_); -} - -// Import a map type. - -Map_type* -Map_type::do_import(Import* imp) -{ - imp->require_c_string("map ["); - Type* key_type = imp->read_type(); - imp->require_c_string("] "); - Type* val_type = imp->read_type(); - return Type::make_map_type(key_type, val_type, imp->location()); -} - -// Make a map type. - -Map_type* -Type::make_map_type(Type* key_type, Type* val_type, Location location) -{ - return new Map_type(key_type, val_type, location); -} - -// Class Channel_type. - -// Hash code. - -unsigned int -Channel_type::do_hash_for_method(Gogo* gogo) const -{ - unsigned int ret = 0; - if (this->may_send_) - ret += 1; - if (this->may_receive_) - ret += 2; - if (this->element_type_ != NULL) - ret += this->element_type_->hash_for_method(gogo) << 2; - return ret << 3; -} - -// Whether this type is the same as T. - -bool -Channel_type::is_identical(const Channel_type* t, - bool errors_are_identical) const -{ - if (!Type::are_identical(this->element_type(), t->element_type(), - errors_are_identical, NULL)) - return false; - return (this->may_send_ == t->may_send_ - && this->may_receive_ == t->may_receive_); -} - -// Return the tree for a channel type. A channel is a pointer to a -// __go_channel struct. The __go_channel struct is defined in -// libgo/runtime/channel.h. - -Btype* -Channel_type::do_get_backend(Gogo* gogo) -{ - static Btype* backend_channel_type; - if (backend_channel_type == NULL) - { - std::vector<Backend::Btyped_identifier> bfields; - Btype* bt = gogo->backend()->struct_type(bfields); - bt = gogo->backend()->named_type("__go_channel", bt, - Linemap::predeclared_location()); - backend_channel_type = gogo->backend()->pointer_type(bt); - } - return backend_channel_type; -} - -// Build a type descriptor for a channel type. - -Type* -Channel_type::make_chan_type_descriptor_type() -{ - static Type* ret; - if (ret == NULL) - { - Type* tdt = Type::make_type_descriptor_type(); - Type* ptdt = Type::make_type_descriptor_ptr_type(); - - Type* uintptr_type = Type::lookup_integer_type("uintptr"); - - Struct_type* sf = - Type::make_builtin_struct_type(3, - "", tdt, - "elem", ptdt, - "dir", uintptr_type); - - ret = Type::make_builtin_named_type("ChanType", sf); - } - - return ret; -} - -// Build a type descriptor for a map type. - -Expression* -Channel_type::do_type_descriptor(Gogo* gogo, Named_type* name) -{ - Location bloc = Linemap::predeclared_location(); - - Type* ctdt = Channel_type::make_chan_type_descriptor_type(); - - const Struct_field_list* fields = ctdt->struct_type()->fields(); - - Expression_list* vals = new Expression_list(); - vals->reserve(3); - - Struct_field_list::const_iterator p = fields->begin(); - go_assert(p->is_field_name("commonType")); - vals->push_back(this->type_descriptor_constructor(gogo, - RUNTIME_TYPE_KIND_CHAN, - name, NULL, true)); - - ++p; - go_assert(p->is_field_name("elem")); - vals->push_back(Expression::make_type_descriptor(this->element_type_, bloc)); - - ++p; - go_assert(p->is_field_name("dir")); - // These bits must match the ones in libgo/runtime/go-type.h. - int val = 0; - if (this->may_receive_) - val |= 1; - if (this->may_send_) - val |= 2; - mpz_t iv; - mpz_init_set_ui(iv, val); - vals->push_back(Expression::make_integer(&iv, p->type(), bloc)); - mpz_clear(iv); - - ++p; - go_assert(p == fields->end()); - - return Expression::make_struct_composite_literal(ctdt, vals, bloc); -} - -// Reflection string. - -void -Channel_type::do_reflection(Gogo* gogo, std::string* ret) const -{ - if (!this->may_send_) - ret->append("<-"); - ret->append("chan"); - if (!this->may_receive_) - ret->append("<-"); - ret->push_back(' '); - this->append_reflection(this->element_type_, gogo, ret); -} - -// Mangled name. - -void -Channel_type::do_mangled_name(Gogo* gogo, std::string* ret) const -{ - ret->push_back('C'); - this->append_mangled_name(this->element_type_, gogo, ret); - if (this->may_send_) - ret->push_back('s'); - if (this->may_receive_) - ret->push_back('r'); - ret->push_back('e'); -} - -// Export. - -void -Channel_type::do_export(Export* exp) const -{ - exp->write_c_string("chan "); - if (this->may_send_ && !this->may_receive_) - exp->write_c_string("-< "); - else if (this->may_receive_ && !this->may_send_) - exp->write_c_string("<- "); - exp->write_type(this->element_type_); -} - -// Import. - -Channel_type* -Channel_type::do_import(Import* imp) -{ - imp->require_c_string("chan "); - - bool may_send; - bool may_receive; - if (imp->match_c_string("-< ")) - { - imp->advance(3); - may_send = true; - may_receive = false; - } - else if (imp->match_c_string("<- ")) - { - imp->advance(3); - may_receive = true; - may_send = false; - } - else - { - may_send = true; - may_receive = true; - } - - Type* element_type = imp->read_type(); - - return Type::make_channel_type(may_send, may_receive, element_type); -} - -// Make a new channel type. - -Channel_type* -Type::make_channel_type(bool send, bool receive, Type* element_type) -{ - return new Channel_type(send, receive, element_type); -} - -// Class Interface_type. - -// Return the list of methods. - -const Typed_identifier_list* -Interface_type::methods() const -{ - go_assert(this->methods_are_finalized_ || saw_errors()); - return this->all_methods_; -} - -// Return the number of methods. - -size_t -Interface_type::method_count() const -{ - go_assert(this->methods_are_finalized_ || saw_errors()); - return this->all_methods_ == NULL ? 0 : this->all_methods_->size(); -} - -// Traversal. - -int -Interface_type::do_traverse(Traverse* traverse) -{ - Typed_identifier_list* methods = (this->methods_are_finalized_ - ? this->all_methods_ - : this->parse_methods_); - if (methods == NULL) - return TRAVERSE_CONTINUE; - return methods->traverse(traverse); -} - -// Finalize the methods. This handles interface inheritance. - -void -Interface_type::finalize_methods() -{ - if (this->methods_are_finalized_) - return; - this->methods_are_finalized_ = true; - if (this->parse_methods_ == NULL) - return; - - this->all_methods_ = new Typed_identifier_list(); - this->all_methods_->reserve(this->parse_methods_->size()); - Typed_identifier_list inherit; - for (Typed_identifier_list::const_iterator pm = - this->parse_methods_->begin(); - pm != this->parse_methods_->end(); - ++pm) - { - const Typed_identifier* p = &*pm; - if (p->name().empty()) - inherit.push_back(*p); - else if (this->find_method(p->name()) == NULL) - this->all_methods_->push_back(*p); - else - error_at(p->location(), "duplicate method %qs", - Gogo::message_name(p->name()).c_str()); - } - - std::vector<Named_type*> seen; - seen.reserve(inherit.size()); - bool issued_recursive_error = false; - while (!inherit.empty()) - { - Type* t = inherit.back().type(); - Location tl = inherit.back().location(); - inherit.pop_back(); - - Interface_type* it = t->interface_type(); - if (it == NULL) - { - if (!t->is_error()) - error_at(tl, "interface contains embedded non-interface"); - continue; - } - if (it == this) - { - if (!issued_recursive_error) - { - error_at(tl, "invalid recursive interface"); - issued_recursive_error = true; - } - continue; - } - - Named_type* nt = t->named_type(); - if (nt != NULL && it->parse_methods_ != NULL) - { - std::vector<Named_type*>::const_iterator q; - for (q = seen.begin(); q != seen.end(); ++q) - { - if (*q == nt) - { - error_at(tl, "inherited interface loop"); - break; - } - } - if (q != seen.end()) - continue; - seen.push_back(nt); - } - - const Typed_identifier_list* imethods = it->parse_methods_; - if (imethods == NULL) - continue; - for (Typed_identifier_list::const_iterator q = imethods->begin(); - q != imethods->end(); - ++q) - { - if (q->name().empty()) - inherit.push_back(*q); - else if (this->find_method(q->name()) == NULL) - this->all_methods_->push_back(Typed_identifier(q->name(), - q->type(), tl)); - else - error_at(tl, "inherited method %qs is ambiguous", - Gogo::message_name(q->name()).c_str()); - } - } - - if (!this->all_methods_->empty()) - this->all_methods_->sort_by_name(); - else - { - delete this->all_methods_; - this->all_methods_ = NULL; - } -} - -// Return the method NAME, or NULL. - -const Typed_identifier* -Interface_type::find_method(const std::string& name) const -{ - go_assert(this->methods_are_finalized_); - if (this->all_methods_ == NULL) - return NULL; - for (Typed_identifier_list::const_iterator p = this->all_methods_->begin(); - p != this->all_methods_->end(); - ++p) - if (p->name() == name) - return &*p; - return NULL; -} - -// Return the method index. - -size_t -Interface_type::method_index(const std::string& name) const -{ - go_assert(this->methods_are_finalized_ && this->all_methods_ != NULL); - size_t ret = 0; - for (Typed_identifier_list::const_iterator p = this->all_methods_->begin(); - p != this->all_methods_->end(); - ++p, ++ret) - if (p->name() == name) - return ret; - go_unreachable(); -} - -// Return whether NAME is an unexported method, for better error -// reporting. - -bool -Interface_type::is_unexported_method(Gogo* gogo, const std::string& name) const -{ - go_assert(this->methods_are_finalized_); - if (this->all_methods_ == NULL) - return false; - for (Typed_identifier_list::const_iterator p = this->all_methods_->begin(); - p != this->all_methods_->end(); - ++p) - { - const std::string& method_name(p->name()); - if (Gogo::is_hidden_name(method_name) - && name == Gogo::unpack_hidden_name(method_name) - && gogo->pack_hidden_name(name, false) != method_name) - return true; - } - return false; -} - -// Whether this type is identical with T. - -bool -Interface_type::is_identical(const Interface_type* t, - bool errors_are_identical) const -{ - // If methods have not been finalized, then we are asking whether - // func redeclarations are the same. This is an error, so for - // simplicity we say they are never the same. - if (!this->methods_are_finalized_ || !t->methods_are_finalized_) - return false; - - // We require the same methods with the same types. The methods - // have already been sorted. - if (this->all_methods_ == NULL || t->all_methods_ == NULL) - return this->all_methods_ == t->all_methods_; - - if (this->assume_identical(this, t) || t->assume_identical(t, this)) - return true; - - Assume_identical* hold_ai = this->assume_identical_; - Assume_identical ai; - ai.t1 = this; - ai.t2 = t; - ai.next = hold_ai; - this->assume_identical_ = &ai; - - Typed_identifier_list::const_iterator p1 = this->all_methods_->begin(); - Typed_identifier_list::const_iterator p2; - for (p2 = t->all_methods_->begin(); p2 != t->all_methods_->end(); ++p1, ++p2) - { - if (p1 == this->all_methods_->end()) - break; - if (p1->name() != p2->name() - || !Type::are_identical(p1->type(), p2->type(), - errors_are_identical, NULL)) - break; - } - - this->assume_identical_ = hold_ai; - - return p1 == this->all_methods_->end() && p2 == t->all_methods_->end(); -} - -// Return true if T1 and T2 are assumed to be identical during a type -// comparison. - -bool -Interface_type::assume_identical(const Interface_type* t1, - const Interface_type* t2) const -{ - for (Assume_identical* p = this->assume_identical_; - p != NULL; - p = p->next) - if ((p->t1 == t1 && p->t2 == t2) || (p->t1 == t2 && p->t2 == t1)) - return true; - return false; -} - -// Whether we can assign the interface type T to this type. The types -// are known to not be identical. An interface assignment is only -// permitted if T is known to implement all methods in THIS. -// Otherwise a type guard is required. - -bool -Interface_type::is_compatible_for_assign(const Interface_type* t, - std::string* reason) const -{ - go_assert(this->methods_are_finalized_ && t->methods_are_finalized_); - if (this->all_methods_ == NULL) - return true; - for (Typed_identifier_list::const_iterator p = this->all_methods_->begin(); - p != this->all_methods_->end(); - ++p) - { - const Typed_identifier* m = t->find_method(p->name()); - if (m == NULL) - { - if (reason != NULL) - { - char buf[200]; - snprintf(buf, sizeof buf, - _("need explicit conversion; missing method %s%s%s"), - open_quote, Gogo::message_name(p->name()).c_str(), - close_quote); - reason->assign(buf); - } - return false; - } - - std::string subreason; - if (!Type::are_identical(p->type(), m->type(), true, &subreason)) - { - if (reason != NULL) - { - std::string n = Gogo::message_name(p->name()); - size_t len = 100 + n.length() + subreason.length(); - char* buf = new char[len]; - if (subreason.empty()) - snprintf(buf, len, _("incompatible type for method %s%s%s"), - open_quote, n.c_str(), close_quote); - else - snprintf(buf, len, - _("incompatible type for method %s%s%s (%s)"), - open_quote, n.c_str(), close_quote, - subreason.c_str()); - reason->assign(buf); - delete[] buf; - } - return false; - } - } - - return true; -} - -// Hash code. - -unsigned int -Interface_type::do_hash_for_method(Gogo*) const -{ - go_assert(this->methods_are_finalized_); - unsigned int ret = 0; - if (this->all_methods_ != NULL) - { - for (Typed_identifier_list::const_iterator p = - this->all_methods_->begin(); - p != this->all_methods_->end(); - ++p) - { - ret = Type::hash_string(p->name(), ret); - // We don't use the method type in the hash, to avoid - // infinite recursion if an interface method uses a type - // which is an interface which inherits from the interface - // itself. - // type T interface { F() interface {T}} - ret <<= 1; - } - } - return ret; -} - -// Return true if T implements the interface. If it does not, and -// REASON is not NULL, set *REASON to a useful error message. - -bool -Interface_type::implements_interface(const Type* t, std::string* reason) const -{ - go_assert(this->methods_are_finalized_); - if (this->all_methods_ == NULL) - return true; - - bool is_pointer = false; - const Named_type* nt = t->named_type(); - const Struct_type* st = t->struct_type(); - // If we start with a named type, we don't dereference it to find - // methods. - if (nt == NULL) - { - const Type* pt = t->points_to(); - if (pt != NULL) - { - // If T is a pointer to a named type, then we need to look at - // the type to which it points. - is_pointer = true; - nt = pt->named_type(); - st = pt->struct_type(); - } - } - - // If we have a named type, get the methods from it rather than from - // any struct type. - if (nt != NULL) - st = NULL; - - // Only named and struct types have methods. - if (nt == NULL && st == NULL) - { - if (reason != NULL) - { - if (t->points_to() != NULL - && t->points_to()->interface_type() != NULL) - reason->assign(_("pointer to interface type has no methods")); - else - reason->assign(_("type has no methods")); - } - return false; - } - - if (nt != NULL ? !nt->has_any_methods() : !st->has_any_methods()) - { - if (reason != NULL) - { - if (t->points_to() != NULL - && t->points_to()->interface_type() != NULL) - reason->assign(_("pointer to interface type has no methods")); - else - reason->assign(_("type has no methods")); - } - return false; - } - - for (Typed_identifier_list::const_iterator p = this->all_methods_->begin(); - p != this->all_methods_->end(); - ++p) - { - bool is_ambiguous = false; - Method* m = (nt != NULL - ? nt->method_function(p->name(), &is_ambiguous) - : st->method_function(p->name(), &is_ambiguous)); - if (m == NULL) - { - if (reason != NULL) - { - std::string n = Gogo::message_name(p->name()); - size_t len = n.length() + 100; - char* buf = new char[len]; - if (is_ambiguous) - snprintf(buf, len, _("ambiguous method %s%s%s"), - open_quote, n.c_str(), close_quote); - else - snprintf(buf, len, _("missing method %s%s%s"), - open_quote, n.c_str(), close_quote); - reason->assign(buf); - delete[] buf; - } - return false; - } - - Function_type *p_fn_type = p->type()->function_type(); - Function_type* m_fn_type = m->type()->function_type(); - go_assert(p_fn_type != NULL && m_fn_type != NULL); - std::string subreason; - if (!p_fn_type->is_identical(m_fn_type, true, true, &subreason)) - { - if (reason != NULL) - { - std::string n = Gogo::message_name(p->name()); - size_t len = 100 + n.length() + subreason.length(); - char* buf = new char[len]; - if (subreason.empty()) - snprintf(buf, len, _("incompatible type for method %s%s%s"), - open_quote, n.c_str(), close_quote); - else - snprintf(buf, len, - _("incompatible type for method %s%s%s (%s)"), - open_quote, n.c_str(), close_quote, - subreason.c_str()); - reason->assign(buf); - delete[] buf; - } - return false; - } - - if (!is_pointer && !m->is_value_method()) - { - if (reason != NULL) - { - std::string n = Gogo::message_name(p->name()); - size_t len = 100 + n.length(); - char* buf = new char[len]; - snprintf(buf, len, - _("method %s%s%s requires a pointer receiver"), - open_quote, n.c_str(), close_quote); - reason->assign(buf); - delete[] buf; - } - return false; - } - - // If the magic //go:nointerface comment was used, the method - // may not be used to implement interfaces. - if (m->nointerface()) - { - if (reason != NULL) - { - std::string n = Gogo::message_name(p->name()); - size_t len = 100 + n.length(); - char* buf = new char[len]; - snprintf(buf, len, - _("method %s%s%s is marked go:nointerface"), - open_quote, n.c_str(), close_quote); - reason->assign(buf); - delete[] buf; - } - return false; - } - } - - return true; -} - -// Return the backend representation of the empty interface type. We -// use the same struct for all empty interfaces. - -Btype* -Interface_type::get_backend_empty_interface_type(Gogo* gogo) -{ - static Btype* empty_interface_type; - if (empty_interface_type == NULL) - { - std::vector<Backend::Btyped_identifier> bfields(2); - - Location bloc = Linemap::predeclared_location(); - - Type* pdt = Type::make_type_descriptor_ptr_type(); - bfields[0].name = "__type_descriptor"; - bfields[0].btype = pdt->get_backend(gogo); - bfields[0].location = bloc; - - Type* vt = Type::make_pointer_type(Type::make_void_type()); - bfields[1].name = "__object"; - bfields[1].btype = vt->get_backend(gogo); - bfields[1].location = bloc; - - empty_interface_type = gogo->backend()->struct_type(bfields); - } - return empty_interface_type; -} - -// Return the fields of a non-empty interface type. This is not -// declared in types.h so that types.h doesn't have to #include -// backend.h. - -static void -get_backend_interface_fields(Gogo* gogo, Interface_type* type, - bool use_placeholder, - std::vector<Backend::Btyped_identifier>* bfields) -{ - Location loc = type->location(); - - std::vector<Backend::Btyped_identifier> mfields(type->methods()->size() + 1); - - Type* pdt = Type::make_type_descriptor_ptr_type(); - mfields[0].name = "__type_descriptor"; - mfields[0].btype = pdt->get_backend(gogo); - mfields[0].location = loc; - - std::string last_name = ""; - size_t i = 1; - for (Typed_identifier_list::const_iterator p = type->methods()->begin(); - p != type->methods()->end(); - ++p, ++i) - { - // The type of the method in Go only includes the parameters. - // The actual method also has a receiver, which is always a - // pointer. We need to add that pointer type here in order to - // generate the correct type for the backend. - Function_type* ft = p->type()->function_type(); - go_assert(ft->receiver() == NULL); - - const Typed_identifier_list* params = ft->parameters(); - Typed_identifier_list* mparams = new Typed_identifier_list(); - if (params != NULL) - mparams->reserve(params->size() + 1); - Type* vt = Type::make_pointer_type(Type::make_void_type()); - mparams->push_back(Typed_identifier("", vt, ft->location())); - if (params != NULL) - { - for (Typed_identifier_list::const_iterator pp = params->begin(); - pp != params->end(); - ++pp) - mparams->push_back(*pp); - } - - Typed_identifier_list* mresults = (ft->results() == NULL - ? NULL - : ft->results()->copy()); - Function_type* mft = Type::make_function_type(NULL, mparams, mresults, - ft->location()); - - mfields[i].name = Gogo::unpack_hidden_name(p->name()); - mfields[i].btype = (use_placeholder - ? mft->get_backend_placeholder(gogo) - : mft->get_backend(gogo)); - mfields[i].location = loc; - // Sanity check: the names should be sorted. - go_assert(p->name() > last_name); - last_name = p->name(); - } - - Btype* methods = gogo->backend()->struct_type(mfields); - - bfields->resize(2); - - (*bfields)[0].name = "__methods"; - (*bfields)[0].btype = gogo->backend()->pointer_type(methods); - (*bfields)[0].location = loc; - - Type* vt = Type::make_pointer_type(Type::make_void_type()); - (*bfields)[1].name = "__object"; - (*bfields)[1].btype = vt->get_backend(gogo); - (*bfields)[1].location = Linemap::predeclared_location(); -} - -// Return a tree for an interface type. An interface is a pointer to -// a struct. The struct has three fields. The first field is a -// pointer to the type descriptor for the dynamic type of the object. -// The second field is a pointer to a table of methods for the -// interface to be used with the object. The third field is the value -// of the object itself. - -Btype* -Interface_type::do_get_backend(Gogo* gogo) -{ - if (this->is_empty()) - return Interface_type::get_backend_empty_interface_type(gogo); - else - { - if (this->interface_btype_ != NULL) - return this->interface_btype_; - this->interface_btype_ = - gogo->backend()->placeholder_struct_type("", this->location_); - std::vector<Backend::Btyped_identifier> bfields; - get_backend_interface_fields(gogo, this, false, &bfields); - if (!gogo->backend()->set_placeholder_struct_type(this->interface_btype_, - bfields)) - this->interface_btype_ = gogo->backend()->error_type(); - return this->interface_btype_; - } -} - -// Finish the backend representation of the methods. - -void -Interface_type::finish_backend_methods(Gogo* gogo) -{ - if (!this->interface_type()->is_empty()) - { - const Typed_identifier_list* methods = this->methods(); - if (methods != NULL) - { - for (Typed_identifier_list::const_iterator p = methods->begin(); - p != methods->end(); - ++p) - p->type()->get_backend(gogo); - } - } -} - -// The type of an interface type descriptor. - -Type* -Interface_type::make_interface_type_descriptor_type() -{ - static Type* ret; - if (ret == NULL) - { - Type* tdt = Type::make_type_descriptor_type(); - Type* ptdt = Type::make_type_descriptor_ptr_type(); - - Type* string_type = Type::lookup_string_type(); - Type* pointer_string_type = Type::make_pointer_type(string_type); - - Struct_type* sm = - Type::make_builtin_struct_type(3, - "name", pointer_string_type, - "pkgPath", pointer_string_type, - "typ", ptdt); - - Type* nsm = Type::make_builtin_named_type("imethod", sm); - - Type* slice_nsm = Type::make_array_type(nsm, NULL); - - Struct_type* s = Type::make_builtin_struct_type(2, - "", tdt, - "methods", slice_nsm); - - ret = Type::make_builtin_named_type("InterfaceType", s); - } - - return ret; -} - -// Build a type descriptor for an interface type. - -Expression* -Interface_type::do_type_descriptor(Gogo* gogo, Named_type* name) -{ - Location bloc = Linemap::predeclared_location(); - - Type* itdt = Interface_type::make_interface_type_descriptor_type(); - - const Struct_field_list* ifields = itdt->struct_type()->fields(); - - Expression_list* ivals = new Expression_list(); - ivals->reserve(2); - - Struct_field_list::const_iterator pif = ifields->begin(); - go_assert(pif->is_field_name("commonType")); - const int rt = RUNTIME_TYPE_KIND_INTERFACE; - ivals->push_back(this->type_descriptor_constructor(gogo, rt, name, NULL, - true)); - - ++pif; - go_assert(pif->is_field_name("methods")); - - Expression_list* methods = new Expression_list(); - if (this->all_methods_ != NULL) - { - Type* elemtype = pif->type()->array_type()->element_type(); - - methods->reserve(this->all_methods_->size()); - for (Typed_identifier_list::const_iterator pm = - this->all_methods_->begin(); - pm != this->all_methods_->end(); - ++pm) - { - const Struct_field_list* mfields = elemtype->struct_type()->fields(); - - Expression_list* mvals = new Expression_list(); - mvals->reserve(3); - - Struct_field_list::const_iterator pmf = mfields->begin(); - go_assert(pmf->is_field_name("name")); - std::string s = Gogo::unpack_hidden_name(pm->name()); - Expression* e = Expression::make_string(s, bloc); - mvals->push_back(Expression::make_unary(OPERATOR_AND, e, bloc)); - - ++pmf; - go_assert(pmf->is_field_name("pkgPath")); - if (!Gogo::is_hidden_name(pm->name())) - mvals->push_back(Expression::make_nil(bloc)); - else - { - s = Gogo::hidden_name_pkgpath(pm->name()); - e = Expression::make_string(s, bloc); - mvals->push_back(Expression::make_unary(OPERATOR_AND, e, bloc)); - } - - ++pmf; - go_assert(pmf->is_field_name("typ")); - mvals->push_back(Expression::make_type_descriptor(pm->type(), bloc)); - - ++pmf; - go_assert(pmf == mfields->end()); - - e = Expression::make_struct_composite_literal(elemtype, mvals, - bloc); - methods->push_back(e); - } - } - - ivals->push_back(Expression::make_slice_composite_literal(pif->type(), - methods, bloc)); - - ++pif; - go_assert(pif == ifields->end()); - - return Expression::make_struct_composite_literal(itdt, ivals, bloc); -} - -// Reflection string. - -void -Interface_type::do_reflection(Gogo* gogo, std::string* ret) const -{ - ret->append("interface {"); - const Typed_identifier_list* methods = this->parse_methods_; - if (methods != NULL) - { - ret->push_back(' '); - for (Typed_identifier_list::const_iterator p = methods->begin(); - p != methods->end(); - ++p) - { - if (p != methods->begin()) - ret->append("; "); - if (p->name().empty()) - this->append_reflection(p->type(), gogo, ret); - else - { - if (!Gogo::is_hidden_name(p->name())) - ret->append(p->name()); - else if (gogo->pkgpath_from_option()) - ret->append(p->name().substr(1)); - else - { - // If no -fgo-pkgpath option, backward compatibility - // for how this used to work before -fgo-pkgpath was - // introduced. - std::string pkgpath = Gogo::hidden_name_pkgpath(p->name()); - ret->append(pkgpath.substr(pkgpath.find('.') + 1)); - ret->push_back('.'); - ret->append(Gogo::unpack_hidden_name(p->name())); - } - std::string sub = p->type()->reflection(gogo); - go_assert(sub.compare(0, 4, "func") == 0); - sub = sub.substr(4); - ret->append(sub); - } - } - ret->push_back(' '); - } - ret->append("}"); -} - -// Mangled name. - -void -Interface_type::do_mangled_name(Gogo* gogo, std::string* ret) const -{ - go_assert(this->methods_are_finalized_); - - ret->push_back('I'); - - const Typed_identifier_list* methods = this->all_methods_; - if (methods != NULL && !this->seen_) - { - this->seen_ = true; - for (Typed_identifier_list::const_iterator p = methods->begin(); - p != methods->end(); - ++p) - { - if (!p->name().empty()) - { - std::string n; - if (!Gogo::is_hidden_name(p->name())) - n = p->name(); - else - { - n = "."; - std::string pkgpath = Gogo::hidden_name_pkgpath(p->name()); - n.append(Gogo::pkgpath_for_symbol(pkgpath)); - n.append(1, '.'); - n.append(Gogo::unpack_hidden_name(p->name())); - } - char buf[20]; - snprintf(buf, sizeof buf, "%u_", - static_cast<unsigned int>(n.length())); - ret->append(buf); - ret->append(n); - } - this->append_mangled_name(p->type(), gogo, ret); - } - this->seen_ = false; - } - - ret->push_back('e'); -} - -// Export. - -void -Interface_type::do_export(Export* exp) const -{ - exp->write_c_string("interface { "); - - const Typed_identifier_list* methods = this->parse_methods_; - if (methods != NULL) - { - for (Typed_identifier_list::const_iterator pm = methods->begin(); - pm != methods->end(); - ++pm) - { - if (pm->name().empty()) - { - exp->write_c_string("? "); - exp->write_type(pm->type()); - } - else - { - exp->write_string(pm->name()); - exp->write_c_string(" ("); - - const Function_type* fntype = pm->type()->function_type(); - - bool first = true; - const Typed_identifier_list* parameters = fntype->parameters(); - if (parameters != NULL) - { - bool is_varargs = fntype->is_varargs(); - for (Typed_identifier_list::const_iterator pp = - parameters->begin(); - pp != parameters->end(); - ++pp) - { - if (first) - first = false; - else - exp->write_c_string(", "); - exp->write_name(pp->name()); - exp->write_c_string(" "); - if (!is_varargs || pp + 1 != parameters->end()) - exp->write_type(pp->type()); - else - { - exp->write_c_string("..."); - Type *pptype = pp->type(); - exp->write_type(pptype->array_type()->element_type()); - } - } - } - - exp->write_c_string(")"); - - const Typed_identifier_list* results = fntype->results(); - if (results != NULL) - { - exp->write_c_string(" "); - if (results->size() == 1 && results->begin()->name().empty()) - exp->write_type(results->begin()->type()); - else - { - first = true; - exp->write_c_string("("); - for (Typed_identifier_list::const_iterator p = - results->begin(); - p != results->end(); - ++p) - { - if (first) - first = false; - else - exp->write_c_string(", "); - exp->write_name(p->name()); - exp->write_c_string(" "); - exp->write_type(p->type()); - } - exp->write_c_string(")"); - } - } - } - - exp->write_c_string("; "); - } - } - - exp->write_c_string("}"); -} - -// Import an interface type. - -Interface_type* -Interface_type::do_import(Import* imp) -{ - imp->require_c_string("interface { "); - - Typed_identifier_list* methods = new Typed_identifier_list; - while (imp->peek_char() != '}') - { - std::string name = imp->read_identifier(); - - if (name == "?") - { - imp->require_c_string(" "); - Type* t = imp->read_type(); - methods->push_back(Typed_identifier("", t, imp->location())); - imp->require_c_string("; "); - continue; - } - - imp->require_c_string(" ("); - - Typed_identifier_list* parameters; - bool is_varargs = false; - if (imp->peek_char() == ')') - parameters = NULL; - else - { - parameters = new Typed_identifier_list; - while (true) - { - std::string name = imp->read_name(); - imp->require_c_string(" "); - - if (imp->match_c_string("...")) - { - imp->advance(3); - is_varargs = true; - } - - Type* ptype = imp->read_type(); - if (is_varargs) - ptype = Type::make_array_type(ptype, NULL); - parameters->push_back(Typed_identifier(name, ptype, - imp->location())); - if (imp->peek_char() != ',') - break; - go_assert(!is_varargs); - imp->require_c_string(", "); - } - } - imp->require_c_string(")"); - - Typed_identifier_list* results; - if (imp->peek_char() != ' ') - results = NULL; - else - { - results = new Typed_identifier_list; - imp->advance(1); - if (imp->peek_char() != '(') - { - Type* rtype = imp->read_type(); - results->push_back(Typed_identifier("", rtype, imp->location())); - } - else - { - imp->advance(1); - while (true) - { - std::string name = imp->read_name(); - imp->require_c_string(" "); - Type* rtype = imp->read_type(); - results->push_back(Typed_identifier(name, rtype, - imp->location())); - if (imp->peek_char() != ',') - break; - imp->require_c_string(", "); - } - imp->require_c_string(")"); - } - } - - Function_type* fntype = Type::make_function_type(NULL, parameters, - results, - imp->location()); - if (is_varargs) - fntype->set_is_varargs(); - methods->push_back(Typed_identifier(name, fntype, imp->location())); - - imp->require_c_string("; "); - } - - imp->require_c_string("}"); - - if (methods->empty()) - { - delete methods; - methods = NULL; - } - - return Type::make_interface_type(methods, imp->location()); -} - -// Make an interface type. - -Interface_type* -Type::make_interface_type(Typed_identifier_list* methods, - Location location) -{ - return new Interface_type(methods, location); -} - -// Make an empty interface type. - -Interface_type* -Type::make_empty_interface_type(Location location) -{ - Interface_type* ret = new Interface_type(NULL, location); - ret->finalize_methods(); - return ret; -} - -// Class Method. - -// Bind a method to an object. - -Expression* -Method::bind_method(Expression* expr, Location location) const -{ - if (this->stub_ == NULL) - { - // When there is no stub object, the binding is determined by - // the child class. - return this->do_bind_method(expr, location); - } - return Expression::make_bound_method(expr, this->stub_, location); -} - -// Return the named object associated with a method. This may only be -// called after methods are finalized. - -Named_object* -Method::named_object() const -{ - if (this->stub_ != NULL) - return this->stub_; - return this->do_named_object(); -} - -// Class Named_method. - -// The type of the method. - -Function_type* -Named_method::do_type() const -{ - if (this->named_object_->is_function()) - return this->named_object_->func_value()->type(); - else if (this->named_object_->is_function_declaration()) - return this->named_object_->func_declaration_value()->type(); - else - go_unreachable(); -} - -// Return the location of the method receiver. - -Location -Named_method::do_receiver_location() const -{ - return this->do_type()->receiver()->location(); -} - -// Bind a method to an object. - -Expression* -Named_method::do_bind_method(Expression* expr, Location location) const -{ - Named_object* no = this->named_object_; - Bound_method_expression* bme = Expression::make_bound_method(expr, no, - location); - // If this is not a local method, and it does not use a stub, then - // the real method expects a different type. We need to cast the - // first argument. - if (this->depth() > 0 && !this->needs_stub_method()) - { - Function_type* ftype = this->do_type(); - go_assert(ftype->is_method()); - Type* frtype = ftype->receiver()->type(); - bme->set_first_argument_type(frtype); - } - return bme; -} - -// Return whether this method should not participate in interfaces. - -bool -Named_method::do_nointerface() const -{ - Named_object* no = this->named_object_; - return no->is_function() && no->func_value()->nointerface(); -} - -// Class Interface_method. - -// Bind a method to an object. - -Expression* -Interface_method::do_bind_method(Expression* expr, - Location location) const -{ - return Expression::make_interface_field_reference(expr, this->name_, - location); -} - -// Class Methods. - -// Insert a new method. Return true if it was inserted, false -// otherwise. - -bool -Methods::insert(const std::string& name, Method* m) -{ - std::pair<Method_map::iterator, bool> ins = - this->methods_.insert(std::make_pair(name, m)); - if (ins.second) - return true; - else - { - Method* old_method = ins.first->second; - if (m->depth() < old_method->depth()) - { - delete old_method; - ins.first->second = m; - return true; - } - else - { - if (m->depth() == old_method->depth()) - old_method->set_is_ambiguous(); - return false; - } - } -} - -// Return the number of unambiguous methods. - -size_t -Methods::count() const -{ - size_t ret = 0; - for (Method_map::const_iterator p = this->methods_.begin(); - p != this->methods_.end(); - ++p) - if (!p->second->is_ambiguous()) - ++ret; - return ret; -} - -// Class Named_type. - -// Return the name of the type. - -const std::string& -Named_type::name() const -{ - return this->named_object_->name(); -} - -// Return the name of the type to use in an error message. - -std::string -Named_type::message_name() const -{ - return this->named_object_->message_name(); -} - -// Whether this is an alias. There are currently only two aliases so -// we just recognize them by name. - -bool -Named_type::is_alias() const -{ - if (!this->is_builtin()) - return false; - const std::string& name(this->name()); - return name == "byte" || name == "rune"; -} - -// Return the base type for this type. We have to be careful about -// circular type definitions, which are invalid but may be seen here. - -Type* -Named_type::named_base() -{ - if (this->seen_) - return this; - this->seen_ = true; - Type* ret = this->type_->base(); - this->seen_ = false; - return ret; -} - -const Type* -Named_type::named_base() const -{ - if (this->seen_) - return this; - this->seen_ = true; - const Type* ret = this->type_->base(); - this->seen_ = false; - return ret; -} - -// Return whether this is an error type. We have to be careful about -// circular type definitions, which are invalid but may be seen here. - -bool -Named_type::is_named_error_type() const -{ - if (this->seen_) - return false; - this->seen_ = true; - bool ret = this->type_->is_error_type(); - this->seen_ = false; - return ret; -} - -// Whether this type is comparable. We have to be careful about -// circular type definitions. - -bool -Named_type::named_type_is_comparable(std::string* reason) const -{ - if (this->seen_) - return false; - this->seen_ = true; - bool ret = Type::are_compatible_for_comparison(true, this->type_, - this->type_, reason); - this->seen_ = false; - return ret; -} - -// Add a method to this type. - -Named_object* -Named_type::add_method(const std::string& name, Function* function) -{ - if (this->local_methods_ == NULL) - this->local_methods_ = new Bindings(NULL); - return this->local_methods_->add_function(name, NULL, function); -} - -// Add a method declaration to this type. - -Named_object* -Named_type::add_method_declaration(const std::string& name, Package* package, - Function_type* type, - Location location) -{ - if (this->local_methods_ == NULL) - this->local_methods_ = new Bindings(NULL); - return this->local_methods_->add_function_declaration(name, package, type, - location); -} - -// Add an existing method to this type. - -void -Named_type::add_existing_method(Named_object* no) -{ - if (this->local_methods_ == NULL) - this->local_methods_ = new Bindings(NULL); - this->local_methods_->add_named_object(no); -} - -// Look for a local method NAME, and returns its named object, or NULL -// if not there. - -Named_object* -Named_type::find_local_method(const std::string& name) const -{ - if (this->local_methods_ == NULL) - return NULL; - return this->local_methods_->lookup(name); -} - -// Return whether NAME is an unexported field or method, for better -// error reporting. - -bool -Named_type::is_unexported_local_method(Gogo* gogo, - const std::string& name) const -{ - Bindings* methods = this->local_methods_; - if (methods != NULL) - { - for (Bindings::const_declarations_iterator p = - methods->begin_declarations(); - p != methods->end_declarations(); - ++p) - { - if (Gogo::is_hidden_name(p->first) - && name == Gogo::unpack_hidden_name(p->first) - && gogo->pack_hidden_name(name, false) != p->first) - return true; - } - } - return false; -} - -// Build the complete list of methods for this type, which means -// recursively including all methods for anonymous fields. Create all -// stub methods. - -void -Named_type::finalize_methods(Gogo* gogo) -{ - if (this->all_methods_ != NULL) - return; - - if (this->local_methods_ != NULL - && (this->points_to() != NULL || this->interface_type() != NULL)) - { - const Bindings* lm = this->local_methods_; - for (Bindings::const_declarations_iterator p = lm->begin_declarations(); - p != lm->end_declarations(); - ++p) - error_at(p->second->location(), - "invalid pointer or interface receiver type"); - delete this->local_methods_; - this->local_methods_ = NULL; - return; - } - - Type::finalize_methods(gogo, this, this->location_, &this->all_methods_); -} - -// Return the method NAME, or NULL if there isn't one or if it is -// ambiguous. Set *IS_AMBIGUOUS if the method exists but is -// ambiguous. - -Method* -Named_type::method_function(const std::string& name, bool* is_ambiguous) const -{ - return Type::method_function(this->all_methods_, name, is_ambiguous); -} - -// Return a pointer to the interface method table for this type for -// the interface INTERFACE. IS_POINTER is true if this is for a -// pointer to THIS. - -tree -Named_type::interface_method_table(Gogo* gogo, const Interface_type* interface, - bool is_pointer) -{ - return Type::interface_method_table(gogo, this, interface, is_pointer, - &this->interface_method_tables_, - &this->pointer_interface_method_tables_); -} - -// Return whether a named type has any hidden fields. - -bool -Named_type::named_type_has_hidden_fields(std::string* reason) const -{ - if (this->seen_) - return false; - this->seen_ = true; - bool ret = this->type_->has_hidden_fields(this, reason); - this->seen_ = false; - return ret; -} - -// Look for a use of a complete type within another type. This is -// used to check that we don't try to use a type within itself. - -class Find_type_use : public Traverse -{ - public: - Find_type_use(Named_type* find_type) - : Traverse(traverse_types), - find_type_(find_type), found_(false) - { } - - // Whether we found the type. - bool - found() const - { return this->found_; } - - protected: - int - type(Type*); - - private: - // The type we are looking for. - Named_type* find_type_; - // Whether we found the type. - bool found_; -}; - -// Check for FIND_TYPE in TYPE. - -int -Find_type_use::type(Type* type) -{ - if (type->named_type() != NULL && this->find_type_ == type->named_type()) - { - this->found_ = true; - return TRAVERSE_EXIT; - } - - // It's OK if we see a reference to the type in any type which is - // essentially a pointer: a pointer, a slice, a function, a map, or - // a channel. - if (type->points_to() != NULL - || type->is_slice_type() - || type->function_type() != NULL - || type->map_type() != NULL - || type->channel_type() != NULL) - return TRAVERSE_SKIP_COMPONENTS; - - // For an interface, a reference to the type in a method type should - // be ignored, but we have to consider direct inheritance. When - // this is called, there may be cases of direct inheritance - // represented as a method with no name. - if (type->interface_type() != NULL) - { - const Typed_identifier_list* methods = type->interface_type()->methods(); - if (methods != NULL) - { - for (Typed_identifier_list::const_iterator p = methods->begin(); - p != methods->end(); - ++p) - { - if (p->name().empty()) - { - if (Type::traverse(p->type(), this) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - } - } - return TRAVERSE_SKIP_COMPONENTS; - } - - // Otherwise, FIND_TYPE_ depends on TYPE, in the sense that we need - // to convert TYPE to the backend representation before we convert - // FIND_TYPE_. - if (type->named_type() != NULL) - { - switch (type->base()->classification()) - { - case Type::TYPE_ERROR: - case Type::TYPE_BOOLEAN: - case Type::TYPE_INTEGER: - case Type::TYPE_FLOAT: - case Type::TYPE_COMPLEX: - case Type::TYPE_STRING: - case Type::TYPE_NIL: - break; - - case Type::TYPE_ARRAY: - case Type::TYPE_STRUCT: - this->find_type_->add_dependency(type->named_type()); - break; - - case Type::TYPE_NAMED: - case Type::TYPE_FORWARD: - go_assert(saw_errors()); - break; - - case Type::TYPE_VOID: - case Type::TYPE_SINK: - case Type::TYPE_FUNCTION: - case Type::TYPE_POINTER: - case Type::TYPE_CALL_MULTIPLE_RESULT: - case Type::TYPE_MAP: - case Type::TYPE_CHANNEL: - case Type::TYPE_INTERFACE: - default: - go_unreachable(); - } - } - - return TRAVERSE_CONTINUE; -} - -// Verify that a named type does not refer to itself. - -bool -Named_type::do_verify() -{ - if (this->is_verified_) - return true; - this->is_verified_ = true; - - Find_type_use find(this); - Type::traverse(this->type_, &find); - if (find.found()) - { - error_at(this->location_, "invalid recursive type %qs", - this->message_name().c_str()); - this->is_error_ = true; - return false; - } - - // Check whether any of the local methods overloads an existing - // struct field or interface method. We don't need to check the - // list of methods against itself: that is handled by the Bindings - // code. - if (this->local_methods_ != NULL) - { - Struct_type* st = this->type_->struct_type(); - if (st != NULL) - { - for (Bindings::const_declarations_iterator p = - this->local_methods_->begin_declarations(); - p != this->local_methods_->end_declarations(); - ++p) - { - const std::string& name(p->first); - if (st != NULL && st->find_local_field(name, NULL) != NULL) - { - error_at(p->second->location(), - "method %qs redeclares struct field name", - Gogo::message_name(name).c_str()); - } - } - } - } - - return true; -} - -// Return whether this type is or contains a pointer. - -bool -Named_type::do_has_pointer() const -{ - if (this->seen_) - return false; - this->seen_ = true; - bool ret = this->type_->has_pointer(); - this->seen_ = false; - return ret; -} - -// Return whether comparisons for this type can use the identity -// function. - -bool -Named_type::do_compare_is_identity(Gogo* gogo) -{ - // We don't use this->seen_ here because compare_is_identity may - // call base() later, and that will mess up if seen_ is set here. - if (this->seen_in_compare_is_identity_) - return false; - this->seen_in_compare_is_identity_ = true; - bool ret = this->type_->compare_is_identity(gogo); - this->seen_in_compare_is_identity_ = false; - return ret; -} - -// Return a hash code. This is used for method lookup. We simply -// hash on the name itself. - -unsigned int -Named_type::do_hash_for_method(Gogo* gogo) const -{ - if (this->is_alias()) - return this->type_->named_type()->do_hash_for_method(gogo); - - const std::string& name(this->named_object()->name()); - unsigned int ret = Type::hash_string(name, 0); - - // GOGO will be NULL here when called from Type_hash_identical. - // That is OK because that is only used for internal hash tables - // where we are going to be comparing named types for equality. In - // other cases, which are cases where the runtime is going to - // compare hash codes to see if the types are the same, we need to - // include the pkgpath in the hash. - if (gogo != NULL && !Gogo::is_hidden_name(name) && !this->is_builtin()) - { - const Package* package = this->named_object()->package(); - if (package == NULL) - ret = Type::hash_string(gogo->pkgpath(), ret); - else - ret = Type::hash_string(package->pkgpath(), ret); - } - - return ret; -} - -// Convert a named type to the backend representation. In order to -// get dependencies right, we fill in a dummy structure for this type, -// then convert all the dependencies, then complete this type. When -// this function is complete, the size of the type is known. - -void -Named_type::convert(Gogo* gogo) -{ - if (this->is_error_ || this->is_converted_) - return; - - this->create_placeholder(gogo); - - // If we are called to turn unsafe.Sizeof into a constant, we may - // not have verified the type yet. We have to make sure it is - // verified, since that sets the list of dependencies. - this->verify(); - - // Convert all the dependencies. If they refer indirectly back to - // this type, they will pick up the intermediate tree we just - // created. - for (std::vector<Named_type*>::const_iterator p = this->dependencies_.begin(); - p != this->dependencies_.end(); - ++p) - (*p)->convert(gogo); - - // Complete this type. - Btype* bt = this->named_btype_; - Type* base = this->type_->base(); - switch (base->classification()) - { - case TYPE_VOID: - case TYPE_BOOLEAN: - case TYPE_INTEGER: - case TYPE_FLOAT: - case TYPE_COMPLEX: - case TYPE_STRING: - case TYPE_NIL: - break; - - case TYPE_MAP: - case TYPE_CHANNEL: - break; - - case TYPE_FUNCTION: - case TYPE_POINTER: - // The size of these types is already correct. We don't worry - // about filling them in until later, when we also track - // circular references. - break; - - case TYPE_STRUCT: - { - std::vector<Backend::Btyped_identifier> bfields; - get_backend_struct_fields(gogo, base->struct_type()->fields(), - true, &bfields); - if (!gogo->backend()->set_placeholder_struct_type(bt, bfields)) - bt = gogo->backend()->error_type(); - } - break; - - case TYPE_ARRAY: - // Slice types were completed in create_placeholder. - if (!base->is_slice_type()) - { - Btype* bet = base->array_type()->get_backend_element(gogo, true); - Bexpression* blen = base->array_type()->get_backend_length(gogo); - if (!gogo->backend()->set_placeholder_array_type(bt, bet, blen)) - bt = gogo->backend()->error_type(); - } - break; - - case TYPE_INTERFACE: - // Interface types were completed in create_placeholder. - break; - - case TYPE_ERROR: - return; - - default: - case TYPE_SINK: - case TYPE_CALL_MULTIPLE_RESULT: - case TYPE_NAMED: - case TYPE_FORWARD: - go_unreachable(); - } - - this->named_btype_ = bt; - this->is_converted_ = true; - this->is_placeholder_ = false; -} - -// Create the placeholder for a named type. This is the first step in -// converting to the backend representation. - -void -Named_type::create_placeholder(Gogo* gogo) -{ - if (this->is_error_) - this->named_btype_ = gogo->backend()->error_type(); - - if (this->named_btype_ != NULL) - return; - - // Create the structure for this type. Note that because we call - // base() here, we don't attempt to represent a named type defined - // as another named type. Instead both named types will point to - // different base representations. - Type* base = this->type_->base(); - Btype* bt; - bool set_name = true; - switch (base->classification()) - { - case TYPE_ERROR: - this->is_error_ = true; - this->named_btype_ = gogo->backend()->error_type(); - return; - - case TYPE_VOID: - case TYPE_BOOLEAN: - case TYPE_INTEGER: - case TYPE_FLOAT: - case TYPE_COMPLEX: - case TYPE_STRING: - case TYPE_NIL: - // These are simple basic types, we can just create them - // directly. - bt = Type::get_named_base_btype(gogo, base); - break; - - case TYPE_MAP: - case TYPE_CHANNEL: - // All maps and channels have the same backend representation. - bt = Type::get_named_base_btype(gogo, base); - break; - - case TYPE_FUNCTION: - case TYPE_POINTER: - { - bool for_function = base->classification() == TYPE_FUNCTION; - bt = gogo->backend()->placeholder_pointer_type(this->name(), - this->location_, - for_function); - set_name = false; - } - break; - - case TYPE_STRUCT: - bt = gogo->backend()->placeholder_struct_type(this->name(), - this->location_); - this->is_placeholder_ = true; - set_name = false; - break; - - case TYPE_ARRAY: - if (base->is_slice_type()) - bt = gogo->backend()->placeholder_struct_type(this->name(), - this->location_); - else - { - bt = gogo->backend()->placeholder_array_type(this->name(), - this->location_); - this->is_placeholder_ = true; - } - set_name = false; - break; - - case TYPE_INTERFACE: - if (base->interface_type()->is_empty()) - bt = Interface_type::get_backend_empty_interface_type(gogo); - else - { - bt = gogo->backend()->placeholder_struct_type(this->name(), - this->location_); - set_name = false; - } - break; - - default: - case TYPE_SINK: - case TYPE_CALL_MULTIPLE_RESULT: - case TYPE_NAMED: - case TYPE_FORWARD: - go_unreachable(); - } - - if (set_name) - bt = gogo->backend()->named_type(this->name(), bt, this->location_); - - this->named_btype_ = bt; - - if (base->is_slice_type()) - { - // We do not record slices as dependencies of other types, - // because we can fill them in completely here with the final - // size. - std::vector<Backend::Btyped_identifier> bfields; - get_backend_slice_fields(gogo, base->array_type(), true, &bfields); - if (!gogo->backend()->set_placeholder_struct_type(bt, bfields)) - this->named_btype_ = gogo->backend()->error_type(); - } - else if (base->interface_type() != NULL - && !base->interface_type()->is_empty()) - { - // We do not record interfaces as dependencies of other types, - // because we can fill them in completely here with the final - // size. - std::vector<Backend::Btyped_identifier> bfields; - get_backend_interface_fields(gogo, base->interface_type(), true, - &bfields); - if (!gogo->backend()->set_placeholder_struct_type(bt, bfields)) - this->named_btype_ = gogo->backend()->error_type(); - } -} - -// Get a tree for a named type. - -Btype* -Named_type::do_get_backend(Gogo* gogo) -{ - if (this->is_error_) - return gogo->backend()->error_type(); - - Btype* bt = this->named_btype_; - - if (!gogo->named_types_are_converted()) - { - // We have not completed converting named types. NAMED_BTYPE_ - // is a placeholder and we shouldn't do anything further. - if (bt != NULL) - return bt; - - // We don't build dependencies for types whose sizes do not - // change or are not relevant, so we may see them here while - // converting types. - this->create_placeholder(gogo); - bt = this->named_btype_; - go_assert(bt != NULL); - return bt; - } - - // We are not converting types. This should only be called if the - // type has already been converted. - if (!this->is_converted_) - { - go_assert(saw_errors()); - return gogo->backend()->error_type(); - } - - go_assert(bt != NULL); - - // Complete the tree. - Type* base = this->type_->base(); - Btype* bt1; - switch (base->classification()) - { - case TYPE_ERROR: - return gogo->backend()->error_type(); - - case TYPE_VOID: - case TYPE_BOOLEAN: - case TYPE_INTEGER: - case TYPE_FLOAT: - case TYPE_COMPLEX: - case TYPE_STRING: - case TYPE_NIL: - case TYPE_MAP: - case TYPE_CHANNEL: - return bt; - - case TYPE_STRUCT: - if (!this->seen_in_get_backend_) - { - this->seen_in_get_backend_ = true; - base->struct_type()->finish_backend_fields(gogo); - this->seen_in_get_backend_ = false; - } - return bt; - - case TYPE_ARRAY: - if (!this->seen_in_get_backend_) - { - this->seen_in_get_backend_ = true; - base->array_type()->finish_backend_element(gogo); - this->seen_in_get_backend_ = false; - } - return bt; - - case TYPE_INTERFACE: - if (!this->seen_in_get_backend_) - { - this->seen_in_get_backend_ = true; - base->interface_type()->finish_backend_methods(gogo); - this->seen_in_get_backend_ = false; - } - return bt; - - case TYPE_FUNCTION: - // Don't build a circular data structure. GENERIC can't handle - // it. - if (this->seen_in_get_backend_) - { - this->is_circular_ = true; - return gogo->backend()->circular_pointer_type(bt, true); - } - this->seen_in_get_backend_ = true; - bt1 = Type::get_named_base_btype(gogo, base); - this->seen_in_get_backend_ = false; - if (this->is_circular_) - bt1 = gogo->backend()->circular_pointer_type(bt, true); - if (!gogo->backend()->set_placeholder_function_type(bt, bt1)) - bt = gogo->backend()->error_type(); - return bt; - - case TYPE_POINTER: - // Don't build a circular data structure. GENERIC can't handle - // it. - if (this->seen_in_get_backend_) - { - this->is_circular_ = true; - return gogo->backend()->circular_pointer_type(bt, false); - } - this->seen_in_get_backend_ = true; - bt1 = Type::get_named_base_btype(gogo, base); - this->seen_in_get_backend_ = false; - if (this->is_circular_) - bt1 = gogo->backend()->circular_pointer_type(bt, false); - if (!gogo->backend()->set_placeholder_pointer_type(bt, bt1)) - bt = gogo->backend()->error_type(); - return bt; - - default: - case TYPE_SINK: - case TYPE_CALL_MULTIPLE_RESULT: - case TYPE_NAMED: - case TYPE_FORWARD: - go_unreachable(); - } - - go_unreachable(); -} - -// Build a type descriptor for a named type. - -Expression* -Named_type::do_type_descriptor(Gogo* gogo, Named_type* name) -{ - if (name == NULL && this->is_alias()) - return this->type_->type_descriptor(gogo, this->type_); - - // If NAME is not NULL, then we don't really want the type - // descriptor for this type; we want the descriptor for the - // underlying type, giving it the name NAME. - return this->named_type_descriptor(gogo, this->type_, - name == NULL ? this : name); -} - -// Add to the reflection string. This is used mostly for the name of -// the type used in a type descriptor, not for actual reflection -// strings. - -void -Named_type::do_reflection(Gogo* gogo, std::string* ret) const -{ - if (this->is_alias()) - { - this->append_reflection(this->type_, gogo, ret); - return; - } - if (!this->is_builtin()) - { - // We handle -fgo-prefix and -fgo-pkgpath differently here for - // compatibility with how the compiler worked before - // -fgo-pkgpath was introduced. When -fgo-pkgpath is specified, - // we use it to make a unique reflection string, so that the - // type canonicalization in the reflect package will work. In - // order to be compatible with the gc compiler, we put tabs into - // the package path, so that the reflect methods can discard it. - const Package* package = this->named_object_->package(); - if (gogo->pkgpath_from_option()) - { - ret->push_back('\t'); - ret->append(package != NULL - ? package->pkgpath_symbol() - : gogo->pkgpath_symbol()); - ret->push_back('\t'); - } - ret->append(package != NULL - ? package->package_name() - : gogo->package_name()); - ret->push_back('.'); - } - if (this->in_function_ != NULL) - { - ret->push_back('\t'); - ret->append(Gogo::unpack_hidden_name(this->in_function_->name())); - ret->push_back('$'); - if (this->in_function_index_ > 0) - { - char buf[30]; - snprintf(buf, sizeof buf, "%u", this->in_function_index_); - ret->append(buf); - ret->push_back('$'); - } - ret->push_back('\t'); - } - ret->append(Gogo::unpack_hidden_name(this->named_object_->name())); -} - -// Get the mangled name. - -void -Named_type::do_mangled_name(Gogo* gogo, std::string* ret) const -{ - if (this->is_alias()) - { - this->append_mangled_name(this->type_, gogo, ret); - return; - } - Named_object* no = this->named_object_; - std::string name; - if (this->is_builtin()) - go_assert(this->in_function_ == NULL); - else - { - const std::string& pkgpath(no->package() == NULL - ? gogo->pkgpath_symbol() - : no->package()->pkgpath_symbol()); - name = pkgpath; - name.append(1, '.'); - if (this->in_function_ != NULL) - { - name.append(Gogo::unpack_hidden_name(this->in_function_->name())); - name.append(1, '$'); - if (this->in_function_index_ > 0) - { - char buf[30]; - snprintf(buf, sizeof buf, "%u", this->in_function_index_); - name.append(buf); - name.append(1, '$'); - } - } - } - name.append(Gogo::unpack_hidden_name(no->name())); - char buf[20]; - snprintf(buf, sizeof buf, "N%u_", static_cast<unsigned int>(name.length())); - ret->append(buf); - ret->append(name); -} - -// Export the type. This is called to export a global type. - -void -Named_type::export_named_type(Export* exp, const std::string&) const -{ - // We don't need to write the name of the type here, because it will - // be written by Export::write_type anyhow. - exp->write_c_string("type "); - exp->write_type(this); - exp->write_c_string(";\n"); -} - -// Import a named type. - -void -Named_type::import_named_type(Import* imp, Named_type** ptype) -{ - imp->require_c_string("type "); - Type *type = imp->read_type(); - *ptype = type->named_type(); - go_assert(*ptype != NULL); - imp->require_c_string(";\n"); -} - -// Export the type when it is referenced by another type. In this -// case Export::export_type will already have issued the name. - -void -Named_type::do_export(Export* exp) const -{ - exp->write_type(this->type_); - - // To save space, we only export the methods directly attached to - // this type. - Bindings* methods = this->local_methods_; - if (methods == NULL) - return; - - exp->write_c_string("\n"); - for (Bindings::const_definitions_iterator p = methods->begin_definitions(); - p != methods->end_definitions(); - ++p) - { - exp->write_c_string(" "); - (*p)->export_named_object(exp); - } - - for (Bindings::const_declarations_iterator p = methods->begin_declarations(); - p != methods->end_declarations(); - ++p) - { - if (p->second->is_function_declaration()) - { - exp->write_c_string(" "); - p->second->export_named_object(exp); - } - } -} - -// Make a named type. - -Named_type* -Type::make_named_type(Named_object* named_object, Type* type, - Location location) -{ - return new Named_type(named_object, type, location); -} - -// Finalize the methods for TYPE. It will be a named type or a struct -// type. This sets *ALL_METHODS to the list of methods, and builds -// all required stubs. - -void -Type::finalize_methods(Gogo* gogo, const Type* type, Location location, - Methods** all_methods) -{ - *all_methods = NULL; - Types_seen types_seen; - Type::add_methods_for_type(type, NULL, 0, false, false, &types_seen, - all_methods); - Type::build_stub_methods(gogo, type, *all_methods, location); -} - -// Add the methods for TYPE to *METHODS. FIELD_INDEXES is used to -// build up the struct field indexes as we go. DEPTH is the depth of -// the field within TYPE. IS_EMBEDDED_POINTER is true if we are -// adding these methods for an anonymous field with pointer type. -// NEEDS_STUB_METHOD is true if we need to use a stub method which -// calls the real method. TYPES_SEEN is used to avoid infinite -// recursion. - -void -Type::add_methods_for_type(const Type* type, - const Method::Field_indexes* field_indexes, - unsigned int depth, - bool is_embedded_pointer, - bool needs_stub_method, - Types_seen* types_seen, - Methods** methods) -{ - // Pointer types may not have methods. - if (type->points_to() != NULL) - return; - - const Named_type* nt = type->named_type(); - if (nt != NULL) - { - std::pair<Types_seen::iterator, bool> ins = types_seen->insert(nt); - if (!ins.second) - return; - } - - if (nt != NULL) - Type::add_local_methods_for_type(nt, field_indexes, depth, - is_embedded_pointer, needs_stub_method, - methods); - - Type::add_embedded_methods_for_type(type, field_indexes, depth, - is_embedded_pointer, needs_stub_method, - types_seen, methods); - - // If we are called with depth > 0, then we are looking at an - // anonymous field of a struct. If such a field has interface type, - // then we need to add the interface methods. We don't want to add - // them when depth == 0, because we will already handle them - // following the usual rules for an interface type. - if (depth > 0) - Type::add_interface_methods_for_type(type, field_indexes, depth, methods); -} - -// Add the local methods for the named type NT to *METHODS. The -// parameters are as for add_methods_to_type. - -void -Type::add_local_methods_for_type(const Named_type* nt, - const Method::Field_indexes* field_indexes, - unsigned int depth, - bool is_embedded_pointer, - bool needs_stub_method, - Methods** methods) -{ - const Bindings* local_methods = nt->local_methods(); - if (local_methods == NULL) - return; - - if (*methods == NULL) - *methods = new Methods(); - - for (Bindings::const_declarations_iterator p = - local_methods->begin_declarations(); - p != local_methods->end_declarations(); - ++p) - { - Named_object* no = p->second; - bool is_value_method = (is_embedded_pointer - || !Type::method_expects_pointer(no)); - Method* m = new Named_method(no, field_indexes, depth, is_value_method, - (needs_stub_method - || (depth > 0 && is_value_method))); - if (!(*methods)->insert(no->name(), m)) - delete m; - } -} - -// Add the embedded methods for TYPE to *METHODS. These are the -// methods attached to anonymous fields. The parameters are as for -// add_methods_to_type. - -void -Type::add_embedded_methods_for_type(const Type* type, - const Method::Field_indexes* field_indexes, - unsigned int depth, - bool is_embedded_pointer, - bool needs_stub_method, - Types_seen* types_seen, - Methods** methods) -{ - // Look for anonymous fields in TYPE. TYPE has fields if it is a - // struct. - const Struct_type* st = type->struct_type(); - if (st == NULL) - return; - - const Struct_field_list* fields = st->fields(); - if (fields == NULL) - return; - - unsigned int i = 0; - for (Struct_field_list::const_iterator pf = fields->begin(); - pf != fields->end(); - ++pf, ++i) - { - if (!pf->is_anonymous()) - continue; - - Type* ftype = pf->type(); - bool is_pointer = false; - if (ftype->points_to() != NULL) - { - ftype = ftype->points_to(); - is_pointer = true; - } - Named_type* fnt = ftype->named_type(); - if (fnt == NULL) - { - // This is an error, but it will be diagnosed elsewhere. - continue; - } - - Method::Field_indexes* sub_field_indexes = new Method::Field_indexes(); - sub_field_indexes->next = field_indexes; - sub_field_indexes->field_index = i; - - Type::add_methods_for_type(fnt, sub_field_indexes, depth + 1, - (is_embedded_pointer || is_pointer), - (needs_stub_method - || is_pointer - || i > 0), - types_seen, - methods); - } -} - -// If TYPE is an interface type, then add its method to *METHODS. -// This is for interface methods attached to an anonymous field. The -// parameters are as for add_methods_for_type. - -void -Type::add_interface_methods_for_type(const Type* type, - const Method::Field_indexes* field_indexes, - unsigned int depth, - Methods** methods) -{ - const Interface_type* it = type->interface_type(); - if (it == NULL) - return; - - const Typed_identifier_list* imethods = it->methods(); - if (imethods == NULL) - return; - - if (*methods == NULL) - *methods = new Methods(); - - for (Typed_identifier_list::const_iterator pm = imethods->begin(); - pm != imethods->end(); - ++pm) - { - Function_type* fntype = pm->type()->function_type(); - if (fntype == NULL) - { - // This is an error, but it should be reported elsewhere - // when we look at the methods for IT. - continue; - } - go_assert(!fntype->is_method()); - fntype = fntype->copy_with_receiver(const_cast<Type*>(type)); - Method* m = new Interface_method(pm->name(), pm->location(), fntype, - field_indexes, depth); - if (!(*methods)->insert(pm->name(), m)) - delete m; - } -} - -// Build stub methods for TYPE as needed. METHODS is the set of -// methods for the type. A stub method may be needed when a type -// inherits a method from an anonymous field. When we need the -// address of the method, as in a type descriptor, we need to build a -// little stub which does the required field dereferences and jumps to -// the real method. LOCATION is the location of the type definition. - -void -Type::build_stub_methods(Gogo* gogo, const Type* type, const Methods* methods, - Location location) -{ - if (methods == NULL) - return; - for (Methods::const_iterator p = methods->begin(); - p != methods->end(); - ++p) - { - Method* m = p->second; - if (m->is_ambiguous() || !m->needs_stub_method()) - continue; - - const std::string& name(p->first); - - // Build a stub method. - - const Function_type* fntype = m->type(); - - static unsigned int counter; - char buf[100]; - snprintf(buf, sizeof buf, "$this%u", counter); - ++counter; - - Type* receiver_type = const_cast<Type*>(type); - if (!m->is_value_method()) - receiver_type = Type::make_pointer_type(receiver_type); - Location receiver_location = m->receiver_location(); - Typed_identifier* receiver = new Typed_identifier(buf, receiver_type, - receiver_location); - - const Typed_identifier_list* fnparams = fntype->parameters(); - Typed_identifier_list* stub_params; - if (fnparams == NULL || fnparams->empty()) - stub_params = NULL; - else - { - // We give each stub parameter a unique name. - stub_params = new Typed_identifier_list(); - for (Typed_identifier_list::const_iterator pp = fnparams->begin(); - pp != fnparams->end(); - ++pp) - { - char pbuf[100]; - snprintf(pbuf, sizeof pbuf, "$p%u", counter); - stub_params->push_back(Typed_identifier(pbuf, pp->type(), - pp->location())); - ++counter; - } - } - - const Typed_identifier_list* fnresults = fntype->results(); - Typed_identifier_list* stub_results; - if (fnresults == NULL || fnresults->empty()) - stub_results = NULL; - else - { - // We create the result parameters without any names, since - // we won't refer to them. - stub_results = new Typed_identifier_list(); - for (Typed_identifier_list::const_iterator pr = fnresults->begin(); - pr != fnresults->end(); - ++pr) - stub_results->push_back(Typed_identifier("", pr->type(), - pr->location())); - } - - Function_type* stub_type = Type::make_function_type(receiver, - stub_params, - stub_results, - fntype->location()); - if (fntype->is_varargs()) - stub_type->set_is_varargs(); - - // We only create the function in the package which creates the - // type. - const Package* package; - if (type->named_type() == NULL) - package = NULL; - else - package = type->named_type()->named_object()->package(); - Named_object* stub; - if (package != NULL) - stub = Named_object::make_function_declaration(name, package, - stub_type, location); - else - { - stub = gogo->start_function(name, stub_type, false, - fntype->location()); - Type::build_one_stub_method(gogo, m, buf, stub_params, - fntype->is_varargs(), location); - gogo->finish_function(fntype->location()); - - if (m->nointerface() && stub->is_function()) - stub->func_value()->set_nointerface(); - } - - m->set_stub_object(stub); - } -} - -// Build a stub method which adjusts the receiver as required to call -// METHOD. RECEIVER_NAME is the name we used for the receiver. -// PARAMS is the list of function parameters. - -void -Type::build_one_stub_method(Gogo* gogo, Method* method, - const char* receiver_name, - const Typed_identifier_list* params, - bool is_varargs, - Location location) -{ - Named_object* receiver_object = gogo->lookup(receiver_name, NULL); - go_assert(receiver_object != NULL); - - Expression* expr = Expression::make_var_reference(receiver_object, location); - expr = Type::apply_field_indexes(expr, method->field_indexes(), location); - if (expr->type()->points_to() == NULL) - expr = Expression::make_unary(OPERATOR_AND, expr, location); - - Expression_list* arguments; - if (params == NULL || params->empty()) - arguments = NULL; - else - { - arguments = new Expression_list(); - for (Typed_identifier_list::const_iterator p = params->begin(); - p != params->end(); - ++p) - { - Named_object* param = gogo->lookup(p->name(), NULL); - go_assert(param != NULL); - Expression* param_ref = Expression::make_var_reference(param, - location); - arguments->push_back(param_ref); - } - } - - Expression* func = method->bind_method(expr, location); - go_assert(func != NULL); - Call_expression* call = Expression::make_call(func, arguments, is_varargs, - location); - call->set_hidden_fields_are_ok(); - size_t count = call->result_count(); - if (count == 0) - gogo->add_statement(Statement::make_statement(call, true)); - else - { - Expression_list* retvals = new Expression_list(); - if (count <= 1) - retvals->push_back(call); - else - { - for (size_t i = 0; i < count; ++i) - retvals->push_back(Expression::make_call_result(call, i)); - } - Return_statement* retstat = Statement::make_return_statement(retvals, - location); - - // We can return values with hidden fields from a stub. This is - // necessary if the method is itself hidden. - retstat->set_hidden_fields_are_ok(); - - gogo->add_statement(retstat); - } -} - -// Apply FIELD_INDEXES to EXPR. The field indexes have to be applied -// in reverse order. - -Expression* -Type::apply_field_indexes(Expression* expr, - const Method::Field_indexes* field_indexes, - Location location) -{ - if (field_indexes == NULL) - return expr; - expr = Type::apply_field_indexes(expr, field_indexes->next, location); - Struct_type* stype = expr->type()->deref()->struct_type(); - go_assert(stype != NULL - && field_indexes->field_index < stype->field_count()); - if (expr->type()->struct_type() == NULL) - { - go_assert(expr->type()->points_to() != NULL); - expr = Expression::make_unary(OPERATOR_MULT, expr, location); - go_assert(expr->type()->struct_type() == stype); - } - return Expression::make_field_reference(expr, field_indexes->field_index, - location); -} - -// Return whether NO is a method for which the receiver is a pointer. - -bool -Type::method_expects_pointer(const Named_object* no) -{ - const Function_type *fntype; - if (no->is_function()) - fntype = no->func_value()->type(); - else if (no->is_function_declaration()) - fntype = no->func_declaration_value()->type(); - else - go_unreachable(); - return fntype->receiver()->type()->points_to() != NULL; -} - -// Given a set of methods for a type, METHODS, return the method NAME, -// or NULL if there isn't one or if it is ambiguous. If IS_AMBIGUOUS -// is not NULL, then set *IS_AMBIGUOUS to true if the method exists -// but is ambiguous (and return NULL). - -Method* -Type::method_function(const Methods* methods, const std::string& name, - bool* is_ambiguous) -{ - if (is_ambiguous != NULL) - *is_ambiguous = false; - if (methods == NULL) - return NULL; - Methods::const_iterator p = methods->find(name); - if (p == methods->end()) - return NULL; - Method* m = p->second; - if (m->is_ambiguous()) - { - if (is_ambiguous != NULL) - *is_ambiguous = true; - return NULL; - } - return m; -} - -// Return a pointer to the interface method table for TYPE for the -// interface INTERFACE. - -tree -Type::interface_method_table(Gogo* gogo, Type* type, - const Interface_type *interface, - bool is_pointer, - Interface_method_tables** method_tables, - Interface_method_tables** pointer_tables) -{ - go_assert(!interface->is_empty()); - - Interface_method_tables** pimt = is_pointer ? method_tables : pointer_tables; - - if (*pimt == NULL) - *pimt = new Interface_method_tables(5); - - std::pair<const Interface_type*, tree> val(interface, NULL_TREE); - std::pair<Interface_method_tables::iterator, bool> ins = (*pimt)->insert(val); - - if (ins.second) - { - // This is a new entry in the hash table. - go_assert(ins.first->second == NULL_TREE); - ins.first->second = gogo->interface_method_table_for_type(interface, - type, - is_pointer); - } - - tree decl = ins.first->second; - if (decl == error_mark_node) - return error_mark_node; - go_assert(decl != NULL_TREE && TREE_CODE(decl) == VAR_DECL); - return build_fold_addr_expr(decl); -} - -// Look for field or method NAME for TYPE. Return an Expression for -// the field or method bound to EXPR. If there is no such field or -// method, give an appropriate error and return an error expression. - -Expression* -Type::bind_field_or_method(Gogo* gogo, const Type* type, Expression* expr, - const std::string& name, - Location location) -{ - if (type->deref()->is_error_type()) - return Expression::make_error(location); - - const Named_type* nt = type->deref()->named_type(); - const Struct_type* st = type->deref()->struct_type(); - const Interface_type* it = type->interface_type(); - - // If this is a pointer to a pointer, then it is possible that the - // pointed-to type has methods. - bool dereferenced = false; - if (nt == NULL - && st == NULL - && it == NULL - && type->points_to() != NULL - && type->points_to()->points_to() != NULL) - { - expr = Expression::make_unary(OPERATOR_MULT, expr, location); - type = type->points_to(); - if (type->deref()->is_error_type()) - return Expression::make_error(location); - nt = type->points_to()->named_type(); - st = type->points_to()->struct_type(); - dereferenced = true; - } - - bool receiver_can_be_pointer = (expr->type()->points_to() != NULL - || expr->is_addressable()); - std::vector<const Named_type*> seen; - bool is_method = false; - bool found_pointer_method = false; - std::string ambig1; - std::string ambig2; - if (Type::find_field_or_method(type, name, receiver_can_be_pointer, - &seen, NULL, &is_method, - &found_pointer_method, &ambig1, &ambig2)) - { - Expression* ret; - if (!is_method) - { - go_assert(st != NULL); - if (type->struct_type() == NULL) - { - go_assert(type->points_to() != NULL); - expr = Expression::make_unary(OPERATOR_MULT, expr, - location); - go_assert(expr->type()->struct_type() == st); - } - ret = st->field_reference(expr, name, location); - } - else if (it != NULL && it->find_method(name) != NULL) - ret = Expression::make_interface_field_reference(expr, name, - location); - else - { - Method* m; - if (nt != NULL) - m = nt->method_function(name, NULL); - else if (st != NULL) - m = st->method_function(name, NULL); - else - go_unreachable(); - go_assert(m != NULL); - if (dereferenced && m->is_value_method()) - { - error_at(location, - "calling value method requires explicit dereference"); - return Expression::make_error(location); - } - if (!m->is_value_method() && expr->type()->points_to() == NULL) - expr = Expression::make_unary(OPERATOR_AND, expr, location); - ret = m->bind_method(expr, location); - } - go_assert(ret != NULL); - return ret; - } - else - { - if (!ambig1.empty()) - error_at(location, "%qs is ambiguous via %qs and %qs", - Gogo::message_name(name).c_str(), ambig1.c_str(), - ambig2.c_str()); - else if (found_pointer_method) - error_at(location, "method requires a pointer receiver"); - else if (nt == NULL && st == NULL && it == NULL) - error_at(location, - ("reference to field %qs in object which " - "has no fields or methods"), - Gogo::message_name(name).c_str()); - else - { - bool is_unexported; - if (!Gogo::is_hidden_name(name)) - is_unexported = false; - else - { - std::string unpacked = Gogo::unpack_hidden_name(name); - seen.clear(); - is_unexported = Type::is_unexported_field_or_method(gogo, type, - unpacked, - &seen); - } - if (is_unexported) - error_at(location, "reference to unexported field or method %qs", - Gogo::message_name(name).c_str()); - else - error_at(location, "reference to undefined field or method %qs", - Gogo::message_name(name).c_str()); - } - return Expression::make_error(location); - } -} - -// Look in TYPE for a field or method named NAME, return true if one -// is found. This looks through embedded anonymous fields and handles -// ambiguity. If a method is found, sets *IS_METHOD to true; -// otherwise, if a field is found, set it to false. If -// RECEIVER_CAN_BE_POINTER is false, then the receiver is a value -// whose address can not be taken. SEEN is used to avoid infinite -// recursion on invalid types. - -// When returning false, this sets *FOUND_POINTER_METHOD if we found a -// method we couldn't use because it requires a pointer. LEVEL is -// used for recursive calls, and can be NULL for a non-recursive call. -// When this function returns false because it finds that the name is -// ambiguous, it will store a path to the ambiguous names in *AMBIG1 -// and *AMBIG2. If the name is not found at all, *AMBIG1 and *AMBIG2 -// will be unchanged. - -// This function just returns whether or not there is a field or -// method, and whether it is a field or method. It doesn't build an -// expression to refer to it. If it is a method, we then look in the -// list of all methods for the type. If it is a field, the search has -// to be done again, looking only for fields, and building up the -// expression as we go. - -bool -Type::find_field_or_method(const Type* type, - const std::string& name, - bool receiver_can_be_pointer, - std::vector<const Named_type*>* seen, - int* level, - bool* is_method, - bool* found_pointer_method, - std::string* ambig1, - std::string* ambig2) -{ - // Named types can have locally defined methods. - const Named_type* nt = type->named_type(); - if (nt == NULL && type->points_to() != NULL) - nt = type->points_to()->named_type(); - if (nt != NULL) - { - Named_object* no = nt->find_local_method(name); - if (no != NULL) - { - if (receiver_can_be_pointer || !Type::method_expects_pointer(no)) - { - *is_method = true; - return true; - } - - // Record that we have found a pointer method in order to - // give a better error message if we don't find anything - // else. - *found_pointer_method = true; - } - - for (std::vector<const Named_type*>::const_iterator p = seen->begin(); - p != seen->end(); - ++p) - { - if (*p == nt) - { - // We've already seen this type when searching for methods. - return false; - } - } - } - - // Interface types can have methods. - const Interface_type* it = type->interface_type(); - if (it != NULL && it->find_method(name) != NULL) - { - *is_method = true; - return true; - } - - // Struct types can have fields. They can also inherit fields and - // methods from anonymous fields. - const Struct_type* st = type->deref()->struct_type(); - if (st == NULL) - return false; - const Struct_field_list* fields = st->fields(); - if (fields == NULL) - return false; - - if (nt != NULL) - seen->push_back(nt); - - int found_level = 0; - bool found_is_method = false; - std::string found_ambig1; - std::string found_ambig2; - const Struct_field* found_parent = NULL; - for (Struct_field_list::const_iterator pf = fields->begin(); - pf != fields->end(); - ++pf) - { - if (pf->is_field_name(name)) - { - *is_method = false; - if (nt != NULL) - seen->pop_back(); - return true; - } - - if (!pf->is_anonymous()) - continue; - - if (pf->type()->deref()->is_error_type() - || pf->type()->deref()->is_undefined()) - continue; - - Named_type* fnt = pf->type()->named_type(); - if (fnt == NULL) - fnt = pf->type()->deref()->named_type(); - go_assert(fnt != NULL); - - int sublevel = level == NULL ? 1 : *level + 1; - bool sub_is_method; - std::string subambig1; - std::string subambig2; - bool subfound = Type::find_field_or_method(fnt, - name, - receiver_can_be_pointer, - seen, - &sublevel, - &sub_is_method, - found_pointer_method, - &subambig1, - &subambig2); - if (!subfound) - { - if (!subambig1.empty()) - { - // The name was found via this field, but is ambiguous. - // if the ambiguity is lower or at the same level as - // anything else we have already found, then we want to - // pass the ambiguity back to the caller. - if (found_level == 0 || sublevel <= found_level) - { - found_ambig1 = (Gogo::message_name(pf->field_name()) - + '.' + subambig1); - found_ambig2 = (Gogo::message_name(pf->field_name()) - + '.' + subambig2); - found_level = sublevel; - } - } - } - else - { - // The name was found via this field. Use the level to see - // if we want to use this one, or whether it introduces an - // ambiguity. - if (found_level == 0 || sublevel < found_level) - { - found_level = sublevel; - found_is_method = sub_is_method; - found_ambig1.clear(); - found_ambig2.clear(); - found_parent = &*pf; - } - else if (sublevel > found_level) - ; - else if (found_ambig1.empty()) - { - // We found an ambiguity. - go_assert(found_parent != NULL); - found_ambig1 = Gogo::message_name(found_parent->field_name()); - found_ambig2 = Gogo::message_name(pf->field_name()); - } - else - { - // We found an ambiguity, but we already know of one. - // Just report the earlier one. - } - } - } - - // Here if we didn't find anything FOUND_LEVEL is 0. If we found - // something ambiguous, FOUND_LEVEL is not 0 and FOUND_AMBIG1 and - // FOUND_AMBIG2 are not empty. If we found the field, FOUND_LEVEL - // is not 0 and FOUND_AMBIG1 and FOUND_AMBIG2 are empty. - - if (nt != NULL) - seen->pop_back(); - - if (found_level == 0) - return false; - else if (!found_ambig1.empty()) - { - go_assert(!found_ambig1.empty()); - ambig1->assign(found_ambig1); - ambig2->assign(found_ambig2); - if (level != NULL) - *level = found_level; - return false; - } - else - { - if (level != NULL) - *level = found_level; - *is_method = found_is_method; - return true; - } -} - -// Return whether NAME is an unexported field or method for TYPE. - -bool -Type::is_unexported_field_or_method(Gogo* gogo, const Type* type, - const std::string& name, - std::vector<const Named_type*>* seen) -{ - const Named_type* nt = type->named_type(); - if (nt == NULL) - nt = type->deref()->named_type(); - if (nt != NULL) - { - if (nt->is_unexported_local_method(gogo, name)) - return true; - - for (std::vector<const Named_type*>::const_iterator p = seen->begin(); - p != seen->end(); - ++p) - { - if (*p == nt) - { - // We've already seen this type. - return false; - } - } - } - - const Interface_type* it = type->interface_type(); - if (it != NULL && it->is_unexported_method(gogo, name)) - return true; - - type = type->deref(); - - const Struct_type* st = type->struct_type(); - if (st != NULL && st->is_unexported_local_field(gogo, name)) - return true; - - if (st == NULL) - return false; - - const Struct_field_list* fields = st->fields(); - if (fields == NULL) - return false; - - if (nt != NULL) - seen->push_back(nt); - - for (Struct_field_list::const_iterator pf = fields->begin(); - pf != fields->end(); - ++pf) - { - if (pf->is_anonymous() - && !pf->type()->deref()->is_error_type() - && !pf->type()->deref()->is_undefined()) - { - Named_type* subtype = pf->type()->named_type(); - if (subtype == NULL) - subtype = pf->type()->deref()->named_type(); - if (subtype == NULL) - { - // This is an error, but it will be diagnosed elsewhere. - continue; - } - if (Type::is_unexported_field_or_method(gogo, subtype, name, seen)) - { - if (nt != NULL) - seen->pop_back(); - return true; - } - } - } - - if (nt != NULL) - seen->pop_back(); - - return false; -} - -// Class Forward_declaration. - -Forward_declaration_type::Forward_declaration_type(Named_object* named_object) - : Type(TYPE_FORWARD), - named_object_(named_object->resolve()), warned_(false) -{ - go_assert(this->named_object_->is_unknown() - || this->named_object_->is_type_declaration()); -} - -// Return the named object. - -Named_object* -Forward_declaration_type::named_object() -{ - return this->named_object_->resolve(); -} - -const Named_object* -Forward_declaration_type::named_object() const -{ - return this->named_object_->resolve(); -} - -// Return the name of the forward declared type. - -const std::string& -Forward_declaration_type::name() const -{ - return this->named_object()->name(); -} - -// Warn about a use of a type which has been declared but not defined. - -void -Forward_declaration_type::warn() const -{ - Named_object* no = this->named_object_->resolve(); - if (no->is_unknown()) - { - // The name was not defined anywhere. - if (!this->warned_) - { - error_at(this->named_object_->location(), - "use of undefined type %qs", - no->message_name().c_str()); - this->warned_ = true; - } - } - else if (no->is_type_declaration()) - { - // The name was seen as a type, but the type was never defined. - if (no->type_declaration_value()->using_type()) - { - error_at(this->named_object_->location(), - "use of undefined type %qs", - no->message_name().c_str()); - this->warned_ = true; - } - } - else - { - // The name was defined, but not as a type. - if (!this->warned_) - { - error_at(this->named_object_->location(), "expected type"); - this->warned_ = true; - } - } -} - -// Get the base type of a declaration. This gives an error if the -// type has not yet been defined. - -Type* -Forward_declaration_type::real_type() -{ - if (this->is_defined()) - return this->named_object()->type_value(); - else - { - this->warn(); - return Type::make_error_type(); - } -} - -const Type* -Forward_declaration_type::real_type() const -{ - if (this->is_defined()) - return this->named_object()->type_value(); - else - { - this->warn(); - return Type::make_error_type(); - } -} - -// Return whether the base type is defined. - -bool -Forward_declaration_type::is_defined() const -{ - return this->named_object()->is_type(); -} - -// Add a method. This is used when methods are defined before the -// type. - -Named_object* -Forward_declaration_type::add_method(const std::string& name, - Function* function) -{ - Named_object* no = this->named_object(); - if (no->is_unknown()) - no->declare_as_type(); - return no->type_declaration_value()->add_method(name, function); -} - -// Add a method declaration. This is used when methods are declared -// before the type. - -Named_object* -Forward_declaration_type::add_method_declaration(const std::string& name, - Package* package, - Function_type* type, - Location location) -{ - Named_object* no = this->named_object(); - if (no->is_unknown()) - no->declare_as_type(); - Type_declaration* td = no->type_declaration_value(); - return td->add_method_declaration(name, package, type, location); -} - -// Traversal. - -int -Forward_declaration_type::do_traverse(Traverse* traverse) -{ - if (this->is_defined() - && Type::traverse(this->real_type(), traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - return TRAVERSE_CONTINUE; -} - -// Verify the type. - -bool -Forward_declaration_type::do_verify() -{ - if (!this->is_defined() && !this->is_nil_constant_as_type()) - { - this->warn(); - return false; - } - return true; -} - -// Get the backend representation for the type. - -Btype* -Forward_declaration_type::do_get_backend(Gogo* gogo) -{ - if (this->is_defined()) - return Type::get_named_base_btype(gogo, this->real_type()); - - if (this->warned_) - return gogo->backend()->error_type(); - - // We represent an undefined type as a struct with no fields. That - // should work fine for the backend, since the same case can arise - // in C. - std::vector<Backend::Btyped_identifier> fields; - Btype* bt = gogo->backend()->struct_type(fields); - return gogo->backend()->named_type(this->name(), bt, - this->named_object()->location()); -} - -// Build a type descriptor for a forwarded type. - -Expression* -Forward_declaration_type::do_type_descriptor(Gogo* gogo, Named_type* name) -{ - Location ploc = Linemap::predeclared_location(); - if (!this->is_defined()) - return Expression::make_error(ploc); - else - { - Type* t = this->real_type(); - if (name != NULL) - return this->named_type_descriptor(gogo, t, name); - else - return Expression::make_type_descriptor(t, ploc); - } -} - -// The reflection string. - -void -Forward_declaration_type::do_reflection(Gogo* gogo, std::string* ret) const -{ - this->append_reflection(this->real_type(), gogo, ret); -} - -// The mangled name. - -void -Forward_declaration_type::do_mangled_name(Gogo* gogo, std::string* ret) const -{ - if (this->is_defined()) - this->append_mangled_name(this->real_type(), gogo, ret); - else - { - const Named_object* no = this->named_object(); - std::string name; - if (no->package() == NULL) - name = gogo->pkgpath_symbol(); - else - name = no->package()->pkgpath_symbol(); - name += '.'; - name += Gogo::unpack_hidden_name(no->name()); - char buf[20]; - snprintf(buf, sizeof buf, "N%u_", - static_cast<unsigned int>(name.length())); - ret->append(buf); - ret->append(name); - } -} - -// Export a forward declaration. This can happen when a defined type -// refers to a type which is only declared (and is presumably defined -// in some other file in the same package). - -void -Forward_declaration_type::do_export(Export*) const -{ - // If there is a base type, that should be exported instead of this. - go_assert(!this->is_defined()); - - // We don't output anything. -} - -// Make a forward declaration. - -Type* -Type::make_forward_declaration(Named_object* named_object) -{ - return new Forward_declaration_type(named_object); -} - -// Class Typed_identifier_list. - -// Sort the entries by name. - -struct Typed_identifier_list_sort -{ - public: - bool - operator()(const Typed_identifier& t1, const Typed_identifier& t2) const - { return t1.name() < t2.name(); } -}; - -void -Typed_identifier_list::sort_by_name() -{ - std::sort(this->entries_.begin(), this->entries_.end(), - Typed_identifier_list_sort()); -} - -// Traverse types. - -int -Typed_identifier_list::traverse(Traverse* traverse) -{ - for (Typed_identifier_list::const_iterator p = this->begin(); - p != this->end(); - ++p) - { - if (Type::traverse(p->type(), traverse) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - return TRAVERSE_CONTINUE; -} - -// Copy the list. - -Typed_identifier_list* -Typed_identifier_list::copy() const -{ - Typed_identifier_list* ret = new Typed_identifier_list(); - for (Typed_identifier_list::const_iterator p = this->begin(); - p != this->end(); - ++p) - ret->push_back(Typed_identifier(p->name(), p->type(), p->location())); - return ret; -} diff --git a/gcc-4.8.1/gcc/go/gofrontend/types.h b/gcc-4.8.1/gcc/go/gofrontend/types.h deleted file mode 100644 index 3922a634f..000000000 --- a/gcc-4.8.1/gcc/go/gofrontend/types.h +++ /dev/null @@ -1,3085 +0,0 @@ -// types.h -- Go frontend types. -*- C++ -*- - -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#ifndef GO_TYPES_H -#define GO_TYPES_H - -#include "go-linemap.h" - -class Gogo; -class Package; -class Traverse; -class Typed_identifier; -class Typed_identifier_list; -class Integer_type; -class Float_type; -class Complex_type; -class String_type; -class Function_type; -class Struct_field; -class Struct_field_list; -class Struct_type; -class Pointer_type; -class Array_type; -class Map_type; -class Channel_type; -class Interface_type; -class Named_type; -class Forward_declaration_type; -class Method; -class Methods; -class Type_hash_identical; -class Type_identical; -class Expression; -class Expression_list; -class Call_expression; -class Field_reference_expression; -class Bound_method_expression; -class Bindings; -class Named_object; -class Function; -class Translate_context; -class Export; -class Import; -class Btype; -class Bexpression; -class Bvariable; - -// Type codes used in type descriptors. These must match the values -// in libgo/runtime/go-type.h. They also match the values in the gc -// compiler in src/cmd/gc/reflect.c and src/pkg/runtime/type.go, -// although this is not required. - -static const int RUNTIME_TYPE_KIND_BOOL = 1; -static const int RUNTIME_TYPE_KIND_INT = 2; -static const int RUNTIME_TYPE_KIND_INT8 = 3; -static const int RUNTIME_TYPE_KIND_INT16 = 4; -static const int RUNTIME_TYPE_KIND_INT32 = 5; -static const int RUNTIME_TYPE_KIND_INT64 = 6; -static const int RUNTIME_TYPE_KIND_UINT = 7; -static const int RUNTIME_TYPE_KIND_UINT8 = 8; -static const int RUNTIME_TYPE_KIND_UINT16 = 9; -static const int RUNTIME_TYPE_KIND_UINT32 = 10; -static const int RUNTIME_TYPE_KIND_UINT64 = 11; -static const int RUNTIME_TYPE_KIND_UINTPTR = 12; -static const int RUNTIME_TYPE_KIND_FLOAT32 = 13; -static const int RUNTIME_TYPE_KIND_FLOAT64 = 14; -static const int RUNTIME_TYPE_KIND_COMPLEX64 = 15; -static const int RUNTIME_TYPE_KIND_COMPLEX128 = 16; -static const int RUNTIME_TYPE_KIND_ARRAY = 17; -static const int RUNTIME_TYPE_KIND_CHAN = 18; -static const int RUNTIME_TYPE_KIND_FUNC = 19; -static const int RUNTIME_TYPE_KIND_INTERFACE = 20; -static const int RUNTIME_TYPE_KIND_MAP = 21; -static const int RUNTIME_TYPE_KIND_PTR = 22; -static const int RUNTIME_TYPE_KIND_SLICE = 23; -static const int RUNTIME_TYPE_KIND_STRING = 24; -static const int RUNTIME_TYPE_KIND_STRUCT = 25; -static const int RUNTIME_TYPE_KIND_UNSAFE_POINTER = 26; - -static const int RUNTIME_TYPE_KIND_NO_POINTERS = (1 << 7); - -// To build the complete list of methods for a named type we need to -// gather all methods from anonymous fields. Those methods may -// require an arbitrary set of indirections and field offsets. There -// is also the possibility of ambiguous methods, which we could ignore -// except that we want to give a better error message for that case. -// This is a base class. There are two types of methods: named -// methods, and methods which are inherited from an anonymous field of -// interface type. - -class Method -{ - public: - // For methods in anonymous types we need to know the sequence of - // field references used to extract the pointer to pass to the - // method. Since each method for a particular anonymous field will - // have the sequence of field indexes, and since the indexes can be - // shared going down the chain, we use a manually managed linked - // list. The first entry in the list is the field index for the - // last field, the one passed to the method. - - struct Field_indexes - { - const Field_indexes* next; - unsigned int field_index; - }; - - virtual ~Method() - { } - - // Get the list of field indexes. - const Field_indexes* - field_indexes() const - { return this->field_indexes_; } - - // Get the depth. - unsigned int - depth() const - { return this->depth_; } - - // Return whether this is a value method--a method which does not - // require a pointer expression. - bool - is_value_method() const - { return this->is_value_method_; } - - // Return whether we need a stub method--this is true if we can't - // just pass the main object to the method. - bool - needs_stub_method() const - { return this->needs_stub_method_; } - - // Return whether this is an ambiguous method name. - bool - is_ambiguous() const - { return this->is_ambiguous_; } - - // Note that this method is ambiguous. - void - set_is_ambiguous() - { this->is_ambiguous_ = true; } - - // Return the type of the method. - Function_type* - type() const - { return this->do_type(); } - - // Return the location of the method receiver. - Location - receiver_location() const - { return this->do_receiver_location(); } - - // Return an expression which binds this method to EXPR. This is - // something which can be used with a function call. - Expression* - bind_method(Expression* expr, Location location) const; - - // Return the named object for this method. This may only be called - // after methods are finalized. - Named_object* - named_object() const; - - // Get the stub object. - Named_object* - stub_object() const - { - go_assert(this->stub_ != NULL); - return this->stub_; - } - - // Set the stub object. - void - set_stub_object(Named_object* no) - { - go_assert(this->stub_ == NULL); - this->stub_ = no; - } - - // Return true if this method should not participate in any - // interfaces. - bool - nointerface() const - { return this->do_nointerface(); } - - protected: - // These objects are only built by the child classes. - Method(const Field_indexes* field_indexes, unsigned int depth, - bool is_value_method, bool needs_stub_method) - : field_indexes_(field_indexes), depth_(depth), stub_(NULL), - is_value_method_(is_value_method), needs_stub_method_(needs_stub_method), - is_ambiguous_(false) - { } - - // The named object for this method. - virtual Named_object* - do_named_object() const = 0; - - // The type of the method. - virtual Function_type* - do_type() const = 0; - - // Return the location of the method receiver. - virtual Location - do_receiver_location() const = 0; - - // Bind a method to an object. - virtual Expression* - do_bind_method(Expression* expr, Location location) const = 0; - - // Return whether this method should not participate in interfaces. - virtual bool - do_nointerface() const = 0; - - private: - // The sequence of field indexes used for this method. If this is - // NULL, then the method is defined for the current type. - const Field_indexes* field_indexes_; - // The depth at which this method was found. - unsigned int depth_; - // If a stub method is required, this is its object. This is only - // set after stub methods are built in finalize_methods. - Named_object* stub_; - // Whether this is a value method--a method that does not require a - // pointer. - bool is_value_method_; - // Whether a stub method is required. - bool needs_stub_method_; - // Whether this method is ambiguous. - bool is_ambiguous_; -}; - -// A named method. This is what you get with a method declaration, -// either directly on the type, or inherited from some anonymous -// embedded field. - -class Named_method : public Method -{ - public: - Named_method(Named_object* named_object, const Field_indexes* field_indexes, - unsigned int depth, bool is_value_method, - bool needs_stub_method) - : Method(field_indexes, depth, is_value_method, needs_stub_method), - named_object_(named_object) - { } - - protected: - // Get the Named_object for the method. - Named_object* - do_named_object() const - { return this->named_object_; } - - // The type of the method. - Function_type* - do_type() const; - - // Return the location of the method receiver. - Location - do_receiver_location() const; - - // Bind a method to an object. - Expression* - do_bind_method(Expression* expr, Location location) const; - - // Return whether this method should not participate in interfaces. - bool - do_nointerface() const; - - private: - // The method itself. For a method which needs a stub, this starts - // out as the underlying method, and is later replaced with the stub - // method. - Named_object* named_object_; -}; - -// An interface method. This is used when an interface appears as an -// anonymous field in a named struct. - -class Interface_method : public Method -{ - public: - Interface_method(const std::string& name, Location location, - Function_type* fntype, const Field_indexes* field_indexes, - unsigned int depth) - : Method(field_indexes, depth, true, true), - name_(name), location_(location), fntype_(fntype) - { } - - protected: - // Get the Named_object for the method. This should never be - // called, as we always create a stub. - Named_object* - do_named_object() const - { go_unreachable(); } - - // The type of the method. - Function_type* - do_type() const - { return this->fntype_; } - - // Return the location of the method receiver. - Location - do_receiver_location() const - { return this->location_; } - - // Bind a method to an object. - Expression* - do_bind_method(Expression* expr, Location location) const; - - // Return whether this method should not participate in interfaces. - bool - do_nointerface() const - { return false; } - - private: - // The name of the interface method to call. - std::string name_; - // The location of the definition of the interface method. - Location location_; - // The type of the interface method. - Function_type* fntype_; -}; - -// A mapping from method name to Method. This is a wrapper around a -// hash table. - -class Methods -{ - private: - typedef Unordered_map(std::string, Method*) Method_map; - - public: - typedef Method_map::const_iterator const_iterator; - - Methods() - : methods_() - { } - - // Insert a new method. Returns true if it was inserted, false if - // it was overidden or ambiguous. - bool - insert(const std::string& name, Method* m); - - // The number of (unambiguous) methods. - size_t - count() const; - - // Iterate. - const_iterator - begin() const - { return this->methods_.begin(); } - - const_iterator - end() const - { return this->methods_.end(); } - - // Lookup. - const_iterator - find(const std::string& name) const - { return this->methods_.find(name); } - - private: - Method_map methods_; -}; - -// The base class for all types. - -class Type -{ - public: - // The types of types. - enum Type_classification - { - TYPE_ERROR, - TYPE_VOID, - TYPE_BOOLEAN, - TYPE_INTEGER, - TYPE_FLOAT, - TYPE_COMPLEX, - TYPE_STRING, - TYPE_SINK, - TYPE_FUNCTION, - TYPE_POINTER, - TYPE_NIL, - TYPE_CALL_MULTIPLE_RESULT, - TYPE_STRUCT, - TYPE_ARRAY, - TYPE_MAP, - TYPE_CHANNEL, - TYPE_INTERFACE, - TYPE_NAMED, - TYPE_FORWARD - }; - - virtual ~Type(); - - // Creators. - - static Type* - make_error_type(); - - static Type* - make_void_type(); - - // Get the unnamed bool type. - static Type* - make_boolean_type(); - - // Get the named type "bool". - static Named_type* - lookup_bool_type(); - - // Make the named type "bool". - static Named_type* - make_named_bool_type(); - - // Make an abstract integer type. - static Integer_type* - make_abstract_integer_type(); - - // Make an abstract type for a character constant. - static Integer_type* - make_abstract_character_type(); - - // Make a named integer type with a specified size. - // RUNTIME_TYPE_KIND is the code to use in reflection information, - // to distinguish int and int32. - static Named_type* - make_integer_type(const char* name, bool is_unsigned, int bits, - int runtime_type_kind); - - // Look up a named integer type. - static Named_type* - lookup_integer_type(const char* name); - - // Make an abstract floating point type. - static Float_type* - make_abstract_float_type(); - - // Make a named floating point type with a specific size. - // RUNTIME_TYPE_KIND is the code to use in reflection information, - // to distinguish float and float32. - static Named_type* - make_float_type(const char* name, int bits, int runtime_type_kind); - - // Look up a named float type. - static Named_type* - lookup_float_type(const char* name); - - // Make an abstract complex type. - static Complex_type* - make_abstract_complex_type(); - - // Make a named complex type with a specific size. - // RUNTIME_TYPE_KIND is the code to use in reflection information, - // to distinguish complex and complex64. - static Named_type* - make_complex_type(const char* name, int bits, int runtime_type_kind); - - // Look up a named complex type. - static Named_type* - lookup_complex_type(const char* name); - - // Get the unnamed string type. - static Type* - make_string_type(); - - // Get the named type "string". - static Named_type* - lookup_string_type(); - - // Make the named type "string". - static Named_type* - make_named_string_type(); - - static Type* - make_sink_type(); - - static Function_type* - make_function_type(Typed_identifier* receiver, - Typed_identifier_list* parameters, - Typed_identifier_list* results, - Location); - - static Pointer_type* - make_pointer_type(Type*); - - static Type* - make_nil_type(); - - static Type* - make_call_multiple_result_type(Call_expression*); - - static Struct_type* - make_struct_type(Struct_field_list* fields, Location); - - static Array_type* - make_array_type(Type* element_type, Expression* length); - - static Map_type* - make_map_type(Type* key_type, Type* value_type, Location); - - static Channel_type* - make_channel_type(bool send, bool receive, Type*); - - static Interface_type* - make_interface_type(Typed_identifier_list* methods, Location); - - static Interface_type* - make_empty_interface_type(Location); - - static Type* - make_type_descriptor_type(); - - static Type* - make_type_descriptor_ptr_type(); - - static Named_type* - make_named_type(Named_object*, Type*, Location); - - static Type* - make_forward_declaration(Named_object*); - - // Traverse a type. - static int - traverse(Type*, Traverse*); - - // Verify the type. This is called after parsing, and verifies that - // types are complete and meet the language requirements. This - // returns false if the type is invalid and we should not continue - // traversing it. - bool - verify() - { return this->do_verify(); } - - // Return true if two types are identical. If ERRORS_ARE_IDENTICAL, - // returns that an erroneous type is identical to any other type; - // this is used to avoid cascading errors. If this returns false, - // and REASON is not NULL, it may set *REASON. - static bool - are_identical(const Type* lhs, const Type* rhs, bool errors_are_identical, - std::string* reason); - - // Return true if two types are compatible for use in a binary - // operation, other than a shift, comparison, or channel send. This - // is an equivalence relation. - static bool - are_compatible_for_binop(const Type* t1, const Type* t2); - - // Return true if two types are compatible for use with the - // comparison operator. IS_EQUALITY_OP is true if this is an - // equality comparison, false if it is an ordered comparison. This - // is an equivalence relation. If this returns false, and REASON is - // not NULL, it sets *REASON. - static bool - are_compatible_for_comparison(bool is_equality_op, const Type *t1, - const Type *t2, std::string* reason); - - // Return true if a type is comparable with itself. This is true of - // most types, but false for, e.g., function types. - bool - is_comparable() const - { return Type::are_compatible_for_comparison(true, this, this, NULL); } - - // Return true if a value with type RHS is assignable to a variable - // with type LHS. This is not an equivalence relation. If this - // returns false, and REASON is not NULL, it sets *REASON. - static bool - are_assignable(const Type* lhs, const Type* rhs, std::string* reason); - - // Return true if a value with type RHS is assignable to a variable - // with type LHS, ignoring any assignment of hidden fields - // (unexported fields of a type imported from another package). - // This is like the are_assignable method. - static bool - are_assignable_hidden_ok(const Type* lhs, const Type* rhs, - std::string* reason); - - // Return true if a value with type RHS may be converted to type - // LHS. If this returns false, and REASON is not NULL, it sets - // *REASON. - static bool - are_convertible(const Type* lhs, const Type* rhs, std::string* reason); - - // Whether this type has any hidden fields which are not visible in - // the current compilation, such as a field whose name begins with a - // lower case letter in a struct imported from a different package. - // WITHIN is not NULL if we are looking at fields in a named type. - bool - has_hidden_fields(const Named_type* within, std::string* reason) const; - - // Return true if values of this type can be compared using an - // identity function which gets nothing but a pointer to the value - // and a size. - bool - compare_is_identity(Gogo* gogo) - { return this->do_compare_is_identity(gogo); } - - // Return a hash code for this type for the method hash table. - // Types which are equivalent according to are_identical will have - // the same hash code. - unsigned int - hash_for_method(Gogo*) const; - - // Return the type classification. - Type_classification - classification() const - { return this->classification_; } - - // Return the base type for this type. This looks through forward - // declarations and names. Using this with a forward declaration - // which has not been defined will return an error type. - Type* - base(); - - const Type* - base() const; - - // Return the type skipping defined forward declarations. If this - // type is a forward declaration which has not been defined, it will - // return the Forward_declaration_type. This differs from base() in - // that it will return a Named_type, and for a - // Forward_declaration_type which is not defined it will return that - // type rather than an error type. - Type* - forwarded(); - - const Type* - forwarded() const; - - // Return true if this is a basic type: a type which is not composed - // of other types, and is not void. - bool - is_basic_type() const; - - // Return true if this is an abstract type--an integer, floating - // point, or complex type whose size has not been determined. - bool - is_abstract() const; - - // Return a non-abstract version of an abstract type. - Type* - make_non_abstract_type(); - - // Return true if this type is or contains a pointer. This - // determines whether the garbage collector needs to look at a value - // of this type. - bool - has_pointer() const - { return this->do_has_pointer(); } - - // Return true if this is the error type. This returns false for a - // type which is not defined, as it is called by the parser before - // all types are defined. - bool - is_error_type() const; - - // Return true if this is the error type or if the type is - // undefined. If the type is undefined, this will give an error. - // This should only be called after parsing is complete. - bool - is_error() const - { return this->base()->is_error_type(); } - - // Return true if this is a void type. - bool - is_void_type() const - { return this->classification_ == TYPE_VOID; } - - // If this is an integer type, return the Integer_type. Otherwise, - // return NULL. This is a controlled dynamic_cast. - Integer_type* - integer_type() - { return this->convert<Integer_type, TYPE_INTEGER>(); } - - const Integer_type* - integer_type() const - { return this->convert<const Integer_type, TYPE_INTEGER>(); } - - // If this is a floating point type, return the Float_type. - // Otherwise, return NULL. This is a controlled dynamic_cast. - Float_type* - float_type() - { return this->convert<Float_type, TYPE_FLOAT>(); } - - const Float_type* - float_type() const - { return this->convert<const Float_type, TYPE_FLOAT>(); } - - // If this is a complex type, return the Complex_type. Otherwise, - // return NULL. - Complex_type* - complex_type() - { return this->convert<Complex_type, TYPE_COMPLEX>(); } - - const Complex_type* - complex_type() const - { return this->convert<const Complex_type, TYPE_COMPLEX>(); } - - // Return whether this is a numeric type. - bool - is_numeric_type() const - { - Type_classification tc = this->base()->classification_; - return tc == TYPE_INTEGER || tc == TYPE_FLOAT || tc == TYPE_COMPLEX; - } - - // Return true if this is a boolean type. - bool - is_boolean_type() const - { return this->base()->classification_ == TYPE_BOOLEAN; } - - // Return true if this is an abstract boolean type. - bool - is_abstract_boolean_type() const - { return this->classification_ == TYPE_BOOLEAN; } - - // Return true if this is a string type. - bool - is_string_type() const - { return this->base()->classification_ == TYPE_STRING; } - - // Return true if this is an abstract string type. - bool - is_abstract_string_type() const - { return this->classification_ == TYPE_STRING; } - - // Return true if this is the sink type. This is the type of the - // blank identifier _. - bool - is_sink_type() const - { return this->base()->classification_ == TYPE_SINK; } - - // If this is a function type, return it. Otherwise, return NULL. - Function_type* - function_type() - { return this->convert<Function_type, TYPE_FUNCTION>(); } - - const Function_type* - function_type() const - { return this->convert<const Function_type, TYPE_FUNCTION>(); } - - // If this is a pointer type, return the type to which it points. - // Otherwise, return NULL. - Type* - points_to() const; - - // If this is a pointer type, return the type to which it points. - // Otherwise, return the type itself. - Type* - deref() - { - Type* pt = this->points_to(); - return pt != NULL ? pt : this; - } - - const Type* - deref() const - { - const Type* pt = this->points_to(); - return pt != NULL ? pt : this; - } - - // Return true if this is the nil type. We don't use base() here, - // because this can be called during parse, and there is no way to - // name the nil type anyhow. - bool - is_nil_type() const - { return this->classification_ == TYPE_NIL; } - - // Return true if this is the predeclared constant nil being used as - // a type. This is what the parser produces for type switches which - // use "case nil". - bool - is_nil_constant_as_type() const; - - // Return true if this is the return type of a function which - // returns multiple values. - bool - is_call_multiple_result_type() const - { return this->base()->classification_ == TYPE_CALL_MULTIPLE_RESULT; } - - // If this is a struct type, return it. Otherwise, return NULL. - Struct_type* - struct_type() - { return this->convert<Struct_type, TYPE_STRUCT>(); } - - const Struct_type* - struct_type() const - { return this->convert<const Struct_type, TYPE_STRUCT>(); } - - // If this is an array type, return it. Otherwise, return NULL. - Array_type* - array_type() - { return this->convert<Array_type, TYPE_ARRAY>(); } - - const Array_type* - array_type() const - { return this->convert<const Array_type, TYPE_ARRAY>(); } - - // Return whether if this is a slice type. - bool - is_slice_type() const; - - // If this is a map type, return it. Otherwise, return NULL. - Map_type* - map_type() - { return this->convert<Map_type, TYPE_MAP>(); } - - const Map_type* - map_type() const - { return this->convert<const Map_type, TYPE_MAP>(); } - - // If this is a channel type, return it. Otherwise, return NULL. - Channel_type* - channel_type() - { return this->convert<Channel_type, TYPE_CHANNEL>(); } - - const Channel_type* - channel_type() const - { return this->convert<const Channel_type, TYPE_CHANNEL>(); } - - // If this is an interface type, return it. Otherwise, return NULL. - Interface_type* - interface_type() - { return this->convert<Interface_type, TYPE_INTERFACE>(); } - - const Interface_type* - interface_type() const - { return this->convert<const Interface_type, TYPE_INTERFACE>(); } - - // If this is a named type, return it. Otherwise, return NULL. - Named_type* - named_type(); - - const Named_type* - named_type() const; - - // If this is a forward declaration, return it. Otherwise, return - // NULL. - Forward_declaration_type* - forward_declaration_type() - { return this->convert_no_base<Forward_declaration_type, TYPE_FORWARD>(); } - - const Forward_declaration_type* - forward_declaration_type() const - { - return this->convert_no_base<const Forward_declaration_type, - TYPE_FORWARD>(); - } - - // Return true if this type is not yet defined. - bool - is_undefined() const; - - // Return true if this is the unsafe.pointer type. We currently - // represent that as pointer-to-void. - bool - is_unsafe_pointer_type() const - { return this->points_to() != NULL && this->points_to()->is_void_type(); } - - // Look for field or method NAME for TYPE. Return an expression for - // it, bound to EXPR. - static Expression* - bind_field_or_method(Gogo*, const Type* type, Expression* expr, - const std::string& name, Location); - - // Return true if NAME is an unexported field or method of TYPE. - static bool - is_unexported_field_or_method(Gogo*, const Type*, const std::string&, - std::vector<const Named_type*>*); - - // Convert the builtin named types. - static void - convert_builtin_named_types(Gogo*); - - // Return the backend representation of this type. - Btype* - get_backend(Gogo*); - - // Return a placeholder for the backend representation of the type. - // This will return a type of the correct size, but for which some - // of the fields may still need to be completed. - Btype* - get_backend_placeholder(Gogo*); - - // Finish the backend representation of a placeholder. - void - finish_backend(Gogo*, Btype*); - - // Build a type descriptor entry for this type. Return a pointer to - // it. The location is the location which causes us to need the - // entry. - tree - type_descriptor_pointer(Gogo* gogo, Location); - - // Return the type reflection string for this type. - std::string - reflection(Gogo*) const; - - // Return a mangled name for the type. This is a name which can be - // used in assembler code. Identical types should have the same - // manged name. - std::string - mangled_name(Gogo*) const; - - // If the size of the type can be determined, set *PSIZE to the size - // in bytes and return true. Otherwise, return false. This queries - // the backend. - bool - backend_type_size(Gogo*, unsigned int* psize); - - // If the alignment of the type can be determined, set *PALIGN to - // the alignment in bytes and return true. Otherwise, return false. - bool - backend_type_align(Gogo*, unsigned int* palign); - - // If the alignment of a struct field of this type can be - // determined, set *PALIGN to the alignment in bytes and return - // true. Otherwise, return false. - bool - backend_type_field_align(Gogo*, unsigned int* palign); - - // Whether the backend size is known. - bool - is_backend_type_size_known(Gogo*); - - // Get the hash and equality functions for a type. - void - type_functions(Gogo*, Named_type* name, Function_type* hash_fntype, - Function_type* equal_fntype, Named_object** hash_fn, - Named_object** equal_fn); - - // Write the hash and equality type functions. - void - write_specific_type_functions(Gogo*, Named_type*, - const std::string& hash_name, - Function_type* hash_fntype, - const std::string& equal_name, - Function_type* equal_fntype); - - // Export the type. - void - export_type(Export* exp) const - { this->do_export(exp); } - - // Import a type. - static Type* - import_type(Import*); - - protected: - Type(Type_classification); - - // Functions implemented by the child class. - - // Traverse the subtypes. - virtual int - do_traverse(Traverse*); - - // Verify the type. - virtual bool - do_verify() - { return true; } - - virtual bool - do_has_pointer() const - { return false; } - - virtual bool - do_compare_is_identity(Gogo*) = 0; - - virtual unsigned int - do_hash_for_method(Gogo*) const; - - virtual Btype* - do_get_backend(Gogo*) = 0; - - virtual Expression* - do_type_descriptor(Gogo*, Named_type* name) = 0; - - virtual void - do_reflection(Gogo*, std::string*) const = 0; - - virtual void - do_mangled_name(Gogo*, std::string*) const = 0; - - virtual void - do_export(Export*) const; - - // Return whether a method expects a pointer as the receiver. - static bool - method_expects_pointer(const Named_object*); - - // Finalize the methods for a type. - static void - finalize_methods(Gogo*, const Type*, Location, Methods**); - - // Return a method from a set of methods. - static Method* - method_function(const Methods*, const std::string& name, - bool* is_ambiguous); - - // A mapping from interfaces to the associated interface method - // tables for this type. This maps to a decl. - typedef Unordered_map_hash(const Interface_type*, tree, Type_hash_identical, - Type_identical) Interface_method_tables; - - // Return a pointer to the interface method table for TYPE for the - // interface INTERFACE. - static tree - interface_method_table(Gogo* gogo, Type* type, - const Interface_type *interface, bool is_pointer, - Interface_method_tables** method_tables, - Interface_method_tables** pointer_tables); - - // Return a composite literal for the type descriptor entry for a - // type. - static Expression* - type_descriptor(Gogo*, Type*); - - // Return a composite literal for the type descriptor entry for - // TYPE, using NAME as the name of the type. - static Expression* - named_type_descriptor(Gogo*, Type* type, Named_type* name); - - // Return a composite literal for a plain type descriptor for this - // type with the given kind and name. - Expression* - plain_type_descriptor(Gogo*, int runtime_type_kind, Named_type* name); - - // Build a composite literal for the basic type descriptor. - Expression* - type_descriptor_constructor(Gogo*, int runtime_type_kind, Named_type*, - const Methods*, bool only_value_methods); - - // Make a builtin struct type from a list of fields. - static Struct_type* - make_builtin_struct_type(int nfields, ...); - - // Make a builtin named type. - static Named_type* - make_builtin_named_type(const char* name, Type* type); - - // For the benefit of child class reflection string generation. - void - append_reflection(const Type* type, Gogo* gogo, std::string* ret) const - { type->do_reflection(gogo, ret); } - - // For the benefit of child class mangling. - void - append_mangled_name(const Type* type, Gogo* gogo, std::string* ret) const - { type->do_mangled_name(gogo, ret); } - - // Incorporate a string into a hash code. - static unsigned int - hash_string(const std::string&, unsigned int); - - // Return the backend representation for the underlying type of a - // named type. - static Btype* - get_named_base_btype(Gogo* gogo, Type* base_type) - { return base_type->get_btype_without_hash(gogo); } - - private: - // Convert to the desired type classification, or return NULL. This - // is a controlled dynamic_cast. - template<typename Type_class, Type_classification type_classification> - Type_class* - convert() - { - Type* base = this->base(); - return (base->classification_ == type_classification - ? static_cast<Type_class*>(base) - : NULL); - } - - template<typename Type_class, Type_classification type_classification> - const Type_class* - convert() const - { - const Type* base = this->base(); - return (base->classification_ == type_classification - ? static_cast<Type_class*>(base) - : NULL); - } - - template<typename Type_class, Type_classification type_classification> - Type_class* - convert_no_base() - { - return (this->classification_ == type_classification - ? static_cast<Type_class*>(this) - : NULL); - } - - template<typename Type_class, Type_classification type_classification> - const Type_class* - convert_no_base() const - { - return (this->classification_ == type_classification - ? static_cast<Type_class*>(this) - : NULL); - } - - // Support for are_assignable and are_assignable_hidden_ok. - static bool - are_assignable_check_hidden(const Type* lhs, const Type* rhs, - bool check_hidden_fields, std::string* reason); - - // Map unnamed types to type descriptor decls. - typedef Unordered_map_hash(const Type*, Bvariable*, Type_hash_identical, - Type_identical) Type_descriptor_vars; - - static Type_descriptor_vars type_descriptor_vars; - - // Build the type descriptor variable for this type. - void - make_type_descriptor_var(Gogo*); - - // Return the name of the type descriptor variable. If NAME is not - // NULL, it is the name to use. - std::string - type_descriptor_var_name(Gogo*, Named_type* name); - - // Return true if the type descriptor for this type should be - // defined in some other package. If NAME is not NULL, it is the - // name of this type. If this returns true it sets *PACKAGE to the - // package where the type descriptor is defined. - bool - type_descriptor_defined_elsewhere(Named_type* name, const Package** package); - - // Build the hash and equality type functions for a type which needs - // specific functions. - void - specific_type_functions(Gogo*, Named_type*, Function_type* hash_fntype, - Function_type* equal_fntype, Named_object** hash_fn, - Named_object** equal_fn); - - // Build a composite literal for the uncommon type information. - Expression* - uncommon_type_constructor(Gogo*, Type* uncommon_type, - Named_type*, const Methods*, - bool only_value_methods) const; - - // Build a composite literal for the methods. - Expression* - methods_constructor(Gogo*, Type* methods_type, const Methods*, - bool only_value_methods) const; - - // Build a composite literal for one method. - Expression* - method_constructor(Gogo*, Type* method_type, const std::string& name, - const Method*, bool only_value_methods) const; - - static tree - build_receive_return_type(tree type); - - // A hash table we use to avoid infinite recursion. - typedef Unordered_set_hash(const Named_type*, Type_hash_identical, - Type_identical) Types_seen; - - // Add all methods for TYPE to the list of methods for THIS. - static void - add_methods_for_type(const Type* type, const Method::Field_indexes*, - unsigned int depth, bool, bool, Types_seen*, - Methods**); - - static void - add_local_methods_for_type(const Named_type* type, - const Method::Field_indexes*, - unsigned int depth, bool, bool, Methods**); - - static void - add_embedded_methods_for_type(const Type* type, - const Method::Field_indexes*, - unsigned int depth, bool, bool, Types_seen*, - Methods**); - - static void - add_interface_methods_for_type(const Type* type, - const Method::Field_indexes*, - unsigned int depth, Methods**); - - // Build stub methods for a type. - static void - build_stub_methods(Gogo*, const Type* type, const Methods* methods, - Location); - - static void - build_one_stub_method(Gogo*, Method*, const char* receiver_name, - const Typed_identifier_list*, bool is_varargs, - Location); - - static Expression* - apply_field_indexes(Expression*, const Method::Field_indexes*, - Location); - - // Look for a field or method named NAME in TYPE. - static bool - find_field_or_method(const Type* type, const std::string& name, - bool receiver_can_be_pointer, - std::vector<const Named_type*>*, int* level, - bool* is_method, bool* found_pointer_method, - std::string* ambig1, std::string* ambig2); - - // Get the backend representation for a type without looking in the - // hash table for identical types. - Btype* - get_btype_without_hash(Gogo*); - - // A backend type that may be a placeholder. - struct Type_btype_entry - { - Btype *btype; - bool is_placeholder; - }; - - // A mapping from Type to Btype*, used to ensure that the backend - // representation of identical types is identical. This is only - // used for unnamed types. - typedef Unordered_map_hash(const Type*, Type_btype_entry, - Type_hash_identical, Type_identical) Type_btypes; - - static Type_btypes type_btypes; - - // A list of builtin named types. - static std::vector<Named_type*> named_builtin_types; - - // A map from types which need specific type functions to the type - // functions themselves. - typedef std::pair<Named_object*, Named_object*> Hash_equal_fn; - typedef Unordered_map_hash(const Type*, Hash_equal_fn, Type_hash_identical, - Type_identical) Type_functions; - - static Type_functions type_functions_table; - - // The type classification. - Type_classification classification_; - // The backend representation of the type, once it has been - // determined. - Btype* btype_; - // The type descriptor for this type. This starts out as NULL and - // is filled in as needed. - Bvariable* type_descriptor_var_; -}; - -// Type hash table operations. - -class Type_hash_identical -{ - public: - unsigned int - operator()(const Type* type) const - { return type->hash_for_method(NULL); } -}; - -class Type_identical -{ - public: - bool - operator()(const Type* t1, const Type* t2) const - { return Type::are_identical(t1, t2, false, NULL); } -}; - -// An identifier with a type. - -class Typed_identifier -{ - public: - Typed_identifier(const std::string& name, Type* type, - Location location) - : name_(name), type_(type), location_(location) - { } - - // Get the name. - const std::string& - name() const - { return this->name_; } - - // Get the type. - Type* - type() const - { return this->type_; } - - // Return the location where the name was seen. This is not always - // meaningful. - Location - location() const - { return this->location_; } - - // Set the type--sometimes we see the identifier before the type. - void - set_type(Type* type) - { - go_assert(this->type_ == NULL || type->is_error_type()); - this->type_ = type; - } - - private: - // Identifier name. - std::string name_; - // Type. - Type* type_; - // The location where the name was seen. - Location location_; -}; - -// A list of Typed_identifiers. - -class Typed_identifier_list -{ - public: - Typed_identifier_list() - : entries_() - { } - - // Whether the list is empty. - bool - empty() const - { return this->entries_.empty(); } - - // Return the number of entries in the list. - size_t - size() const - { return this->entries_.size(); } - - // Add an entry to the end of the list. - void - push_back(const Typed_identifier& td) - { this->entries_.push_back(td); } - - // Remove an entry from the end of the list. - void - pop_back() - { this->entries_.pop_back(); } - - // Set the type of entry I to TYPE. - void - set_type(size_t i, Type* type) - { - go_assert(i < this->entries_.size()); - this->entries_[i].set_type(type); - } - - // Sort the entries by name. - void - sort_by_name(); - - // Traverse types. - int - traverse(Traverse*); - - // Return the first and last elements. - Typed_identifier& - front() - { return this->entries_.front(); } - - const Typed_identifier& - front() const - { return this->entries_.front(); } - - Typed_identifier& - back() - { return this->entries_.back(); } - - const Typed_identifier& - back() const - { return this->entries_.back(); } - - const Typed_identifier& - at(size_t i) const - { return this->entries_.at(i); } - - void - set(size_t i, const Typed_identifier& t) - { this->entries_.at(i) = t; } - - void - resize(size_t c) - { - go_assert(c <= this->entries_.size()); - this->entries_.resize(c, Typed_identifier("", NULL, - Linemap::unknown_location())); - } - - void - reserve(size_t c) - { this->entries_.reserve(c); } - - // Iterators. - - typedef std::vector<Typed_identifier>::iterator iterator; - typedef std::vector<Typed_identifier>::const_iterator const_iterator; - - iterator - begin() - { return this->entries_.begin(); } - - const_iterator - begin() const - { return this->entries_.begin(); } - - iterator - end() - { return this->entries_.end(); } - - const_iterator - end() const - { return this->entries_.end(); } - - // Return a copy of this list. This returns an independent copy of - // the vector, but does not copy the types. - Typed_identifier_list* - copy() const; - - private: - std::vector<Typed_identifier> entries_; -}; - -// The type of an integer. - -class Integer_type : public Type -{ - public: - // Create a new integer type. - static Named_type* - create_integer_type(const char* name, bool is_unsigned, int bits, - int runtime_type_kind); - - // Look up an existing integer type. - static Named_type* - lookup_integer_type(const char* name); - - // Create an abstract integer type. - static Integer_type* - create_abstract_integer_type(); - - // Create an abstract character type. - static Integer_type* - create_abstract_character_type(); - - // Whether this is an abstract integer type. - bool - is_abstract() const - { return this->is_abstract_; } - - // Whether this is an unsigned type. - bool - is_unsigned() const - { return this->is_unsigned_; } - - // The number of bits. - int - bits() const - { return this->bits_; } - - // Whether this type is the same as T. - bool - is_identical(const Integer_type* t) const; - - // Whether this is the type "byte" or another name for "byte". - bool - is_byte() const - { return this->is_byte_; } - - // Mark this as the "byte" type. - void - set_is_byte() - { this->is_byte_ = true; } - - // Whether this is the type "rune" or another name for "rune". - bool - is_rune() const - { return this->is_rune_; } - - // Mark this as the "rune" type. - void - set_is_rune() - { this->is_rune_ = true; } - -protected: - bool - do_compare_is_identity(Gogo*) - { return true; } - - unsigned int - do_hash_for_method(Gogo*) const; - - Btype* - do_get_backend(Gogo*); - - Expression* - do_type_descriptor(Gogo*, Named_type*); - - void - do_reflection(Gogo*, std::string*) const; - - void - do_mangled_name(Gogo*, std::string*) const; - - private: - Integer_type(bool is_abstract, bool is_unsigned, int bits, - int runtime_type_kind) - : Type(TYPE_INTEGER), - is_abstract_(is_abstract), is_unsigned_(is_unsigned), is_byte_(false), - is_rune_(false), bits_(bits), runtime_type_kind_(runtime_type_kind) - { } - - // Map names of integer types to the types themselves. - typedef std::map<std::string, Named_type*> Named_integer_types; - static Named_integer_types named_integer_types; - - // True if this is an abstract type. - bool is_abstract_; - // True if this is an unsigned type. - bool is_unsigned_; - // True if this is the byte type. - bool is_byte_; - // True if this is the rune type. - bool is_rune_; - // The number of bits. - int bits_; - // The runtime type code used in the type descriptor for this type. - int runtime_type_kind_; -}; - -// The type of a floating point number. - -class Float_type : public Type -{ - public: - // Create a new float type. - static Named_type* - create_float_type(const char* name, int bits, int runtime_type_kind); - - // Look up an existing float type. - static Named_type* - lookup_float_type(const char* name); - - // Create an abstract float type. - static Float_type* - create_abstract_float_type(); - - // Whether this is an abstract float type. - bool - is_abstract() const - { return this->is_abstract_; } - - // The number of bits. - int - bits() const - { return this->bits_; } - - // Whether this type is the same as T. - bool - is_identical(const Float_type* t) const; - - protected: - bool - do_compare_is_identity(Gogo*) - { return false; } - - unsigned int - do_hash_for_method(Gogo*) const; - - Btype* - do_get_backend(Gogo*); - - Expression* - do_type_descriptor(Gogo*, Named_type*); - - void - do_reflection(Gogo*, std::string*) const; - - void - do_mangled_name(Gogo*, std::string*) const; - - private: - Float_type(bool is_abstract, int bits, int runtime_type_kind) - : Type(TYPE_FLOAT), - is_abstract_(is_abstract), bits_(bits), - runtime_type_kind_(runtime_type_kind) - { } - - // Map names of float types to the types themselves. - typedef std::map<std::string, Named_type*> Named_float_types; - static Named_float_types named_float_types; - - // True if this is an abstract type. - bool is_abstract_; - // The number of bits in the floating point value. - int bits_; - // The runtime type code used in the type descriptor for this type. - int runtime_type_kind_; -}; - -// The type of a complex number. - -class Complex_type : public Type -{ - public: - // Create a new complex type. - static Named_type* - create_complex_type(const char* name, int bits, int runtime_type_kind); - - // Look up an existing complex type. - static Named_type* - lookup_complex_type(const char* name); - - // Create an abstract complex type. - static Complex_type* - create_abstract_complex_type(); - - // Whether this is an abstract complex type. - bool - is_abstract() const - { return this->is_abstract_; } - - // The number of bits: 64 or 128. - int bits() const - { return this->bits_; } - - // Whether this type is the same as T. - bool - is_identical(const Complex_type* t) const; - - protected: - bool - do_compare_is_identity(Gogo*) - { return false; } - - unsigned int - do_hash_for_method(Gogo*) const; - - Btype* - do_get_backend(Gogo*); - - Expression* - do_type_descriptor(Gogo*, Named_type*); - - void - do_reflection(Gogo*, std::string*) const; - - void - do_mangled_name(Gogo*, std::string*) const; - - private: - Complex_type(bool is_abstract, int bits, int runtime_type_kind) - : Type(TYPE_COMPLEX), - is_abstract_(is_abstract), bits_(bits), - runtime_type_kind_(runtime_type_kind) - { } - - // Map names of complex types to the types themselves. - typedef std::map<std::string, Named_type*> Named_complex_types; - static Named_complex_types named_complex_types; - - // True if this is an abstract type. - bool is_abstract_; - // The number of bits in the complex value--64 or 128. - int bits_; - // The runtime type code used in the type descriptor for this type. - int runtime_type_kind_; -}; - -// The type of a string. - -class String_type : public Type -{ - public: - String_type() - : Type(TYPE_STRING) - { } - - // Return a tree for the length of STRING. - static tree - length_tree(Gogo*, tree string); - - // Return a tree which points to the bytes of STRING. - static tree - bytes_tree(Gogo*, tree string); - - protected: - bool - do_has_pointer() const - { return true; } - - bool - do_compare_is_identity(Gogo*) - { return false; } - - Btype* - do_get_backend(Gogo*); - - Expression* - do_type_descriptor(Gogo*, Named_type*); - - void - do_reflection(Gogo*, std::string*) const; - - void - do_mangled_name(Gogo*, std::string* ret) const; - - private: - // The named string type. - static Named_type* string_type_; -}; - -// The type of a function. - -class Function_type : public Type -{ - public: - Function_type(Typed_identifier* receiver, Typed_identifier_list* parameters, - Typed_identifier_list* results, Location location) - : Type(TYPE_FUNCTION), - receiver_(receiver), parameters_(parameters), results_(results), - location_(location), is_varargs_(false), is_builtin_(false) - { } - - // Get the receiver. - const Typed_identifier* - receiver() const - { return this->receiver_; } - - // Get the return names and types. - const Typed_identifier_list* - results() const - { return this->results_; } - - // Get the parameter names and types. - const Typed_identifier_list* - parameters() const - { return this->parameters_; } - - // Whether this is a varargs function. - bool - is_varargs() const - { return this->is_varargs_; } - - // Whether this is a builtin function. - bool - is_builtin() const - { return this->is_builtin_; } - - // The location where this type was defined. - Location - location() const - { return this->location_; } - - // Return whether this is a method type. - bool - is_method() const - { return this->receiver_ != NULL; } - - // Whether T is a valid redeclaration of this type. This is called - // when a function is declared more than once. - bool - is_valid_redeclaration(const Function_type* t, std::string*) const; - - // Whether this type is the same as T. - bool - is_identical(const Function_type* t, bool ignore_receiver, - bool errors_are_identical, std::string*) const; - - // Record that this is a varargs function. - void - set_is_varargs() - { this->is_varargs_ = true; } - - // Record that this is a builtin function. - void - set_is_builtin() - { this->is_builtin_ = true; } - - // Import a function type. - static Function_type* - do_import(Import*); - - // Return a copy of this type without a receiver. This is only - // valid for a method type. - Function_type* - copy_without_receiver() const; - - // Return a copy of this type with a receiver. This is used when an - // interface method is attached to a named or struct type. - Function_type* - copy_with_receiver(Type*) const; - - static Type* - make_function_type_descriptor_type(); - - protected: - int - do_traverse(Traverse*); - - // A trampoline function has a pointer which matters for GC. - bool - do_has_pointer() const - { return true; } - - bool - do_compare_is_identity(Gogo*) - { return false; } - - unsigned int - do_hash_for_method(Gogo*) const; - - Btype* - do_get_backend(Gogo*); - - Expression* - do_type_descriptor(Gogo*, Named_type*); - - void - do_reflection(Gogo*, std::string*) const; - - void - do_mangled_name(Gogo*, std::string*) const; - - void - do_export(Export*) const; - - private: - Expression* - type_descriptor_params(Type*, const Typed_identifier*, - const Typed_identifier_list*); - - // The receiver name and type. This will be NULL for a normal - // function, non-NULL for a method. - Typed_identifier* receiver_; - // The parameter names and types. - Typed_identifier_list* parameters_; - // The result names and types. This will be NULL if no result was - // specified. - Typed_identifier_list* results_; - // The location where this type was defined. This exists solely to - // give a location for the fields of the struct if this function - // returns multiple values. - Location location_; - // Whether this function takes a variable number of arguments. - bool is_varargs_; - // Whether this is a special builtin function which can not simply - // be called. This is used for len, cap, etc. - bool is_builtin_; -}; - -// The type of a pointer. - -class Pointer_type : public Type -{ - public: - Pointer_type(Type* to_type) - : Type(TYPE_POINTER), - to_type_(to_type) - {} - - Type* - points_to() const - { return this->to_type_; } - - // Import a pointer type. - static Pointer_type* - do_import(Import*); - - static Type* - make_pointer_type_descriptor_type(); - - protected: - int - do_traverse(Traverse*); - - bool - do_has_pointer() const - { return true; } - - bool - do_compare_is_identity(Gogo*) - { return true; } - - unsigned int - do_hash_for_method(Gogo*) const; - - Btype* - do_get_backend(Gogo*); - - Expression* - do_type_descriptor(Gogo*, Named_type*); - - void - do_reflection(Gogo*, std::string*) const; - - void - do_mangled_name(Gogo*, std::string*) const; - - void - do_export(Export*) const; - - private: - // The type to which this type points. - Type* to_type_; -}; - -// The type of a field in a struct. - -class Struct_field -{ - public: - explicit Struct_field(const Typed_identifier& typed_identifier) - : typed_identifier_(typed_identifier), tag_(NULL) - { } - - // The field name. - const std::string& - field_name() const; - - // Return whether this struct field is named NAME. - bool - is_field_name(const std::string& name) const; - - // The field type. - Type* - type() const - { return this->typed_identifier_.type(); } - - // The field location. - Location - location() const - { return this->typed_identifier_.location(); } - - // Whether the field has a tag. - bool - has_tag() const - { return this->tag_ != NULL; } - - // The tag. - const std::string& - tag() const - { - go_assert(this->tag_ != NULL); - return *this->tag_; - } - - // Whether this is an anonymous field. - bool - is_anonymous() const - { return this->typed_identifier_.name().empty(); } - - // Set the tag. FIXME: This is never freed. - void - set_tag(const std::string& tag) - { this->tag_ = new std::string(tag); } - - // Set the type. This is only used in error cases. - void - set_type(Type* type) - { this->typed_identifier_.set_type(type); } - - private: - // The field name, type, and location. - Typed_identifier typed_identifier_; - // The field tag. This is NULL if the field has no tag. - std::string* tag_; -}; - -// A list of struct fields. - -class Struct_field_list -{ - public: - Struct_field_list() - : entries_() - { } - - // Whether the list is empty. - bool - empty() const - { return this->entries_.empty(); } - - // Return the number of entries. - size_t - size() const - { return this->entries_.size(); } - - // Add an entry to the end of the list. - void - push_back(const Struct_field& sf) - { this->entries_.push_back(sf); } - - // Index into the list. - const Struct_field& - at(size_t i) const - { return this->entries_.at(i); } - - // Last entry in list. - Struct_field& - back() - { return this->entries_.back(); } - - // Iterators. - - typedef std::vector<Struct_field>::iterator iterator; - typedef std::vector<Struct_field>::const_iterator const_iterator; - - iterator - begin() - { return this->entries_.begin(); } - - const_iterator - begin() const - { return this->entries_.begin(); } - - iterator - end() - { return this->entries_.end(); } - - const_iterator - end() const - { return this->entries_.end(); } - - private: - std::vector<Struct_field> entries_; -}; - -// The type of a struct. - -class Struct_type : public Type -{ - public: - Struct_type(Struct_field_list* fields, Location location) - : Type(TYPE_STRUCT), - fields_(fields), location_(location), all_methods_(NULL), - interface_method_tables_(NULL), pointer_interface_method_tables_(NULL) - { } - - // Return the field NAME. This only looks at local fields, not at - // embedded types. If the field is found, and PINDEX is not NULL, - // this sets *PINDEX to the field index. If the field is not found, - // this returns NULL. - const Struct_field* - find_local_field(const std::string& name, unsigned int *pindex) const; - - // Return the field number INDEX. - const Struct_field* - field(unsigned int index) const - { return &this->fields_->at(index); } - - // Get the struct fields. - const Struct_field_list* - fields() const - { return this->fields_; } - - // Return the number of fields. - size_t - field_count() const - { return this->fields_->size(); } - - // Push a new field onto the end of the struct. This is used when - // building a closure variable. - void - push_field(const Struct_field& sf) - { this->fields_->push_back(sf); } - - // Return an expression referring to field NAME in STRUCT_EXPR, or - // NULL if there is no field with that name. - Field_reference_expression* - field_reference(Expression* struct_expr, const std::string& name, - Location) const; - - // Return the total number of fields, including embedded fields. - // This is the number of values that can appear in a conversion to - // this type. - unsigned int - total_field_count() const; - - // Whether this type is identical with T. - bool - is_identical(const Struct_type* t, bool errors_are_identical) const; - - // Whether this struct type has any hidden fields. This returns - // true if any fields have hidden names, or if any non-pointer - // anonymous fields have types with hidden fields. - bool - struct_has_hidden_fields(const Named_type* within, std::string*) const; - - // Return whether NAME is a local field which is not exported. This - // is only used for better error reporting. - bool - is_unexported_local_field(Gogo*, const std::string& name) const; - - // If this is an unnamed struct, build the complete list of methods, - // including those from anonymous fields, and build methods stubs if - // needed. - void - finalize_methods(Gogo*); - - // Return whether this type has any methods. This should only be - // called after the finalize_methods pass. - bool - has_any_methods() const - { return this->all_methods_ != NULL; } - - // Return the methods for tihs type. This should only be called - // after the finalize_methods pass. - const Methods* - methods() const - { return this->all_methods_; } - - // Return the method to use for NAME. This returns NULL if there is - // no such method or if the method is ambiguous. When it returns - // NULL, this sets *IS_AMBIGUOUS if the method name is ambiguous. - Method* - method_function(const std::string& name, bool* is_ambiguous) const; - - // Return a pointer to the interface method table for this type for - // the interface INTERFACE. If IS_POINTER is true, set the type - // descriptor to a pointer to this type, otherwise set it to this - // type. - tree - interface_method_table(Gogo*, const Interface_type* interface, - bool is_pointer); - - // Traverse just the field types of a struct type. - int - traverse_field_types(Traverse* traverse) - { return this->do_traverse(traverse); } - - // If the offset of field INDEX in the backend implementation can be - // determined, set *POFFSET to the offset in bytes and return true. - // Otherwise, return false. - bool - backend_field_offset(Gogo*, unsigned int index, unsigned int* poffset); - - // Finish the backend representation of all the fields. - void - finish_backend_fields(Gogo*); - - // Import a struct type. - static Struct_type* - do_import(Import*); - - static Type* - make_struct_type_descriptor_type(); - - // Write the hash function for this type. - void - write_hash_function(Gogo*, Named_type*, Function_type*, Function_type*); - - // Write the equality function for this type. - void - write_equal_function(Gogo*, Named_type*); - - protected: - int - do_traverse(Traverse*); - - bool - do_verify(); - - bool - do_has_pointer() const; - - bool - do_compare_is_identity(Gogo*); - - unsigned int - do_hash_for_method(Gogo*) const; - - Btype* - do_get_backend(Gogo*); - - Expression* - do_type_descriptor(Gogo*, Named_type*); - - void - do_reflection(Gogo*, std::string*) const; - - void - do_mangled_name(Gogo*, std::string*) const; - - void - do_export(Export*) const; - - private: - // Used to merge method sets of identical unnamed structs. - typedef Unordered_map_hash(Struct_type*, Struct_type*, Type_hash_identical, - Type_identical) Identical_structs; - - static Identical_structs identical_structs; - - // Used to avoid infinite loops in field_reference_depth. - struct Saw_named_type - { - Saw_named_type* next; - Named_type* nt; - }; - - Field_reference_expression* - field_reference_depth(Expression* struct_expr, const std::string& name, - Location, Saw_named_type*, - unsigned int* depth) const; - - // The fields of the struct. - Struct_field_list* fields_; - // The place where the struct was declared. - Location location_; - // If this struct is unnamed, a list of methods. - Methods* all_methods_; - // A mapping from interfaces to the associated interface method - // tables for this type. Only used if this struct is unnamed. - Interface_method_tables* interface_method_tables_; - // A mapping from interfaces to the associated interface method - // tables for pointers to this type. Only used if this struct is - // unnamed. - Interface_method_tables* pointer_interface_method_tables_; -}; - -// The type of an array. - -class Array_type : public Type -{ - public: - Array_type(Type* element_type, Expression* length) - : Type(TYPE_ARRAY), - element_type_(element_type), length_(length), length_tree_(NULL) - { } - - // Return the element type. - Type* - element_type() const - { return this->element_type_; } - - // Return the length. This will return NULL for an open array. - Expression* - length() const - { return this->length_; } - - // Whether this type is identical with T. - bool - is_identical(const Array_type* t, bool errors_are_identical) const; - - // Whether this type has any hidden fields. - bool - array_has_hidden_fields(const Named_type* within, std::string* reason) const - { return this->element_type_->has_hidden_fields(within, reason); } - - // Return a tree for the pointer to the values in an array. - tree - value_pointer_tree(Gogo*, tree array) const; - - // Return a tree for the length of an array with this type. - tree - length_tree(Gogo*, tree array); - - // Return a tree for the capacity of an array with this type. - tree - capacity_tree(Gogo*, tree array); - - // Import an array type. - static Array_type* - do_import(Import*); - - // Return the backend representation of the element type. - Btype* - get_backend_element(Gogo*, bool use_placeholder); - - // Return the backend representation of the length. - Bexpression* - get_backend_length(Gogo*); - - // Finish the backend representation of the element type. - void - finish_backend_element(Gogo*); - - static Type* - make_array_type_descriptor_type(); - - static Type* - make_slice_type_descriptor_type(); - - // Write the hash function for this type. - void - write_hash_function(Gogo*, Named_type*, Function_type*, Function_type*); - - // Write the equality function for this type. - void - write_equal_function(Gogo*, Named_type*); - - protected: - int - do_traverse(Traverse* traverse); - - bool - do_verify(); - - bool - do_has_pointer() const - { - return this->length_ == NULL || this->element_type_->has_pointer(); - } - - bool - do_compare_is_identity(Gogo*); - - unsigned int - do_hash_for_method(Gogo*) const; - - Btype* - do_get_backend(Gogo*); - - Expression* - do_type_descriptor(Gogo*, Named_type*); - - void - do_reflection(Gogo*, std::string*) const; - - void - do_mangled_name(Gogo*, std::string*) const; - - void - do_export(Export*) const; - - private: - bool - verify_length(); - - tree - get_length_tree(Gogo*); - - Expression* - array_type_descriptor(Gogo*, Named_type*); - - Expression* - slice_type_descriptor(Gogo*, Named_type*); - - // The type of elements of the array. - Type* element_type_; - // The number of elements. This may be NULL. - Expression* length_; - // The length as a tree. We only want to compute this once. - tree length_tree_; -}; - -// The type of a map. - -class Map_type : public Type -{ - public: - Map_type(Type* key_type, Type* val_type, Location location) - : Type(TYPE_MAP), - key_type_(key_type), val_type_(val_type), location_(location) - { } - - // Return the key type. - Type* - key_type() const - { return this->key_type_; } - - // Return the value type. - Type* - val_type() const - { return this->val_type_; } - - // Whether this type is identical with T. - bool - is_identical(const Map_type* t, bool errors_are_identical) const; - - // Import a map type. - static Map_type* - do_import(Import*); - - static Type* - make_map_type_descriptor_type(); - - static Type* - make_map_descriptor_type(); - - // Build a map descriptor for this type. Return a pointer to it. - // The location is the location which causes us to need the - // descriptor. - tree - map_descriptor_pointer(Gogo* gogo, Location); - - protected: - int - do_traverse(Traverse*); - - bool - do_verify(); - - bool - do_has_pointer() const - { return true; } - - bool - do_compare_is_identity(Gogo*) - { return false; } - - unsigned int - do_hash_for_method(Gogo*) const; - - Btype* - do_get_backend(Gogo*); - - Expression* - do_type_descriptor(Gogo*, Named_type*); - - void - do_reflection(Gogo*, std::string*) const; - - void - do_mangled_name(Gogo*, std::string*) const; - - void - do_export(Export*) const; - - private: - // Mapping from map types to map descriptors. - typedef Unordered_map_hash(const Map_type*, Bvariable*, Type_hash_identical, - Type_identical) Map_descriptors; - static Map_descriptors map_descriptors; - - Bvariable* - map_descriptor(Gogo*); - - // The key type. - Type* key_type_; - // The value type. - Type* val_type_; - // Where the type was defined. - Location location_; -}; - -// The type of a channel. - -class Channel_type : public Type -{ - public: - Channel_type(bool may_send, bool may_receive, Type* element_type) - : Type(TYPE_CHANNEL), - may_send_(may_send), may_receive_(may_receive), - element_type_(element_type) - { go_assert(may_send || may_receive); } - - // Whether this channel can send data. - bool - may_send() const - { return this->may_send_; } - - // Whether this channel can receive data. - bool - may_receive() const - { return this->may_receive_; } - - // The type of the values that may be sent on this channel. This is - // NULL if any type may be sent. - Type* - element_type() const - { return this->element_type_; } - - // Whether this type is identical with T. - bool - is_identical(const Channel_type* t, bool errors_are_identical) const; - - // Import a channel type. - static Channel_type* - do_import(Import*); - - static Type* - make_chan_type_descriptor_type(); - - protected: - int - do_traverse(Traverse* traverse) - { return Type::traverse(this->element_type_, traverse); } - - bool - do_has_pointer() const - { return true; } - - bool - do_compare_is_identity(Gogo*) - { return true; } - - unsigned int - do_hash_for_method(Gogo*) const; - - Btype* - do_get_backend(Gogo*); - - Expression* - do_type_descriptor(Gogo*, Named_type*); - - void - do_reflection(Gogo*, std::string*) const; - - void - do_mangled_name(Gogo*, std::string*) const; - - void - do_export(Export*) const; - - private: - // Whether this channel can send data. - bool may_send_; - // Whether this channel can receive data. - bool may_receive_; - // The types of elements which may be sent on this channel. If this - // is NULL, it means that any type may be sent. - Type* element_type_; -}; - -// An interface type. - -class Interface_type : public Type -{ - public: - Interface_type(Typed_identifier_list* methods, Location location) - : Type(TYPE_INTERFACE), - parse_methods_(methods), all_methods_(NULL), location_(location), - interface_btype_(NULL), assume_identical_(NULL), - methods_are_finalized_(false), seen_(false) - { go_assert(methods == NULL || !methods->empty()); } - - // The location where the interface type was defined. - Location - location() const - { return this->location_; } - - // Return whether this is an empty interface. - bool - is_empty() const - { - go_assert(this->methods_are_finalized_); - return this->all_methods_ == NULL; - } - - // Return the list of methods. This will return NULL for an empty - // interface. - const Typed_identifier_list* - methods() const; - - // Return the number of methods. - size_t - method_count() const; - - // Return the method NAME, or NULL. - const Typed_identifier* - find_method(const std::string& name) const; - - // Return the zero-based index of method NAME. - size_t - method_index(const std::string& name) const; - - // Finalize the methods. This sets all_methods_. This handles - // interface inheritance. - void - finalize_methods(); - - // Return true if T implements this interface. If this returns - // false, and REASON is not NULL, it sets *REASON to the reason that - // it fails. - bool - implements_interface(const Type* t, std::string* reason) const; - - // Whether this type is identical with T. REASON is as in - // implements_interface. - bool - is_identical(const Interface_type* t, bool errors_are_identical) const; - - // Whether we can assign T to this type. is_identical is known to - // be false. - bool - is_compatible_for_assign(const Interface_type*, std::string* reason) const; - - // Return whether NAME is a method which is not exported. This is - // only used for better error reporting. - bool - is_unexported_method(Gogo*, const std::string& name) const; - - // Import an interface type. - static Interface_type* - do_import(Import*); - - // Make a struct for an empty interface type. - static Btype* - get_backend_empty_interface_type(Gogo*); - - // Finish the backend representation of the method types. - void - finish_backend_methods(Gogo*); - - static Type* - make_interface_type_descriptor_type(); - - protected: - int - do_traverse(Traverse*); - - bool - do_has_pointer() const - { return true; } - - bool - do_compare_is_identity(Gogo*) - { return false; } - - unsigned int - do_hash_for_method(Gogo*) const; - - Btype* - do_get_backend(Gogo*); - - Expression* - do_type_descriptor(Gogo*, Named_type*); - - void - do_reflection(Gogo*, std::string*) const; - - void - do_mangled_name(Gogo*, std::string*) const; - - void - do_export(Export*) const; - - private: - // This type guards against infinite recursion when comparing - // interface types. We keep a list of interface types assumed to be - // identical during comparison. We just keep the list on the stack. - // This permits us to compare cases like - // type I1 interface { F() interface{I1} } - // type I2 interface { F() interface{I2} } - struct Assume_identical - { - Assume_identical* next; - const Interface_type* t1; - const Interface_type* t2; - }; - - bool - assume_identical(const Interface_type*, const Interface_type*) const; - - // The list of methods associated with the interface from the - // parser. This will be NULL for the empty interface. This may - // include unnamed interface types. - Typed_identifier_list* parse_methods_; - // The list of all methods associated with the interface. This - // expands any interface types listed in methods_. It is set by - // finalize_methods. This will be NULL for the empty interface. - Typed_identifier_list* all_methods_; - // The location where the interface was defined. - Location location_; - // The backend representation of this type during backend conversion. - Btype* interface_btype_; - // A list of interface types assumed to be identical during - // interface comparison. - mutable Assume_identical* assume_identical_; - // Whether the methods have been finalized. - bool methods_are_finalized_; - // Used to avoid endless recursion in do_mangled_name. - mutable bool seen_; -}; - -// The value we keep for a named type. This lets us get the right -// name when we convert to trees. Note that we don't actually keep -// the name here; the name is in the Named_object which points to -// this. This object exists to hold a unique tree which represents -// the type. - -class Named_type : public Type -{ - public: - Named_type(Named_object* named_object, Type* type, Location location) - : Type(TYPE_NAMED), - named_object_(named_object), in_function_(NULL), in_function_index_(0), - type_(type), local_methods_(NULL), all_methods_(NULL), - interface_method_tables_(NULL), pointer_interface_method_tables_(NULL), - location_(location), named_btype_(NULL), dependencies_(), - is_visible_(true), is_error_(false), is_placeholder_(false), - is_converted_(false), is_circular_(false), is_verified_(false), - seen_(false), seen_in_compare_is_identity_(false), - seen_in_get_backend_(false) - { } - - // Return the associated Named_object. This holds the actual name. - Named_object* - named_object() - { return this->named_object_; } - - const Named_object* - named_object() const - { return this->named_object_; } - - // Set the Named_object. This is used when we see a type - // declaration followed by a type. - void - set_named_object(Named_object* no) - { this->named_object_ = no; } - - // Return the function in which this type is defined. This will - // return NULL for a type defined in global scope. - const Named_object* - in_function(unsigned int *pindex) const - { - *pindex = this->in_function_index_; - return this->in_function_; - } - - // Set the function in which this type is defined. - void - set_in_function(Named_object* f, unsigned int index) - { - this->in_function_ = f; - this->in_function_index_ = index; - } - - // Return the name of the type. - const std::string& - name() const; - - // Return the name of the type for an error message. The difference - // is that if the type is defined in a different package, this will - // return PACKAGE.NAME. - std::string - message_name() const; - - // Return the underlying type. - Type* - real_type() - { return this->type_; } - - const Type* - real_type() const - { return this->type_; } - - // Return the location. - Location - location() const - { return this->location_; } - - // Whether this type is visible. This only matters when parsing. - bool - is_visible() const - { return this->is_visible_; } - - // Mark this type as visible. - void - set_is_visible() - { this->is_visible_ = true; } - - // Mark this type as invisible. - void - clear_is_visible() - { this->is_visible_ = false; } - - // Whether this is a builtin type. - bool - is_builtin() const - { return Linemap::is_predeclared_location(this->location_); } - - // Whether this is an alias. There are currently two aliases: byte - // and rune. - bool - is_alias() const; - - // Whether this is a circular type: a pointer or function type that - // refers to itself, which is not possible in C. - bool - is_circular() const - { return this->is_circular_; } - - // Return the base type for this type. - Type* - named_base(); - - const Type* - named_base() const; - - // Return whether this is an error type. - bool - is_named_error_type() const; - - // Return whether this type is comparable. If REASON is not NULL, - // set *REASON when returning false. - bool - named_type_is_comparable(std::string* reason) const; - - // Add a method to this type. - Named_object* - add_method(const std::string& name, Function*); - - // Add a method declaration to this type. - Named_object* - add_method_declaration(const std::string& name, Package* package, - Function_type* type, Location location); - - // Add an existing method--one defined before the type itself was - // defined--to a type. - void - add_existing_method(Named_object*); - - // Look up a local method. - Named_object* - find_local_method(const std::string& name) const; - - // Return the list of local methods. - const Bindings* - local_methods() const - { return this->local_methods_; } - - // Build the complete list of methods, including those from - // anonymous fields, and build method stubs if needed. - void - finalize_methods(Gogo*); - - // Return whether this type has any methods. This should only be - // called after the finalize_methods pass. - bool - has_any_methods() const - { return this->all_methods_ != NULL; } - - // Return the methods for this type. This should only be called - // after the finalized_methods pass. - const Methods* - methods() const - { return this->all_methods_; } - - // Return the method to use for NAME. This returns NULL if there is - // no such method or if the method is ambiguous. When it returns - // NULL, this sets *IS_AMBIGUOUS if the method name is ambiguous. - Method* - method_function(const std::string& name, bool *is_ambiguous) const; - - // Return whether NAME is a known field or method which is not - // exported. This is only used for better error reporting. - bool - is_unexported_local_method(Gogo*, const std::string& name) const; - - // Return a pointer to the interface method table for this type for - // the interface INTERFACE. If IS_POINTER is true, set the type - // descriptor to a pointer to this type, otherwise set it to this - // type. - tree - interface_method_table(Gogo*, const Interface_type* interface, - bool is_pointer); - - // Whether this type has any hidden fields. - bool - named_type_has_hidden_fields(std::string* reason) const; - - // Note that a type must be converted to the backend representation - // before we convert this type. - void - add_dependency(Named_type* nt) - { this->dependencies_.push_back(nt); } - - // Return true if the size and alignment of the backend - // representation of this type is known. This is always true after - // types have been converted, but may be false beforehand. - bool - is_named_backend_type_size_known() const - { return this->named_btype_ != NULL && !this->is_placeholder_; } - - // Export the type. - void - export_named_type(Export*, const std::string& name) const; - - // Import a named type. - static void - import_named_type(Import*, Named_type**); - - // Initial conversion to backend representation. - void - convert(Gogo*); - - protected: - int - do_traverse(Traverse* traverse) - { return Type::traverse(this->type_, traverse); } - - bool - do_verify(); - - bool - do_has_pointer() const; - - bool - do_compare_is_identity(Gogo*); - - unsigned int - do_hash_for_method(Gogo*) const; - - Btype* - do_get_backend(Gogo*); - - Expression* - do_type_descriptor(Gogo*, Named_type*); - - void - do_reflection(Gogo*, std::string*) const; - - void - do_mangled_name(Gogo*, std::string* ret) const; - - void - do_export(Export*) const; - - private: - // Create the placeholder during conversion. - void - create_placeholder(Gogo*); - - // A pointer back to the Named_object for this type. - Named_object* named_object_; - // If this type is defined in a function, a pointer back to the - // function in which it is defined. - Named_object* in_function_; - // The index of this type in IN_FUNCTION_. - unsigned int in_function_index_; - // The actual type. - Type* type_; - // The list of methods defined for this type. Any named type can - // have methods. - Bindings* local_methods_; - // The full list of methods for this type, including methods - // declared for anonymous fields. - Methods* all_methods_; - // A mapping from interfaces to the associated interface method - // tables for this type. - Interface_method_tables* interface_method_tables_; - // A mapping from interfaces to the associated interface method - // tables for pointers to this type. - Interface_method_tables* pointer_interface_method_tables_; - // The location where this type was defined. - Location location_; - // The backend representation of this type during backend - // conversion. This is used to avoid endless recursion when a named - // type refers to itself. - Btype* named_btype_; - // A list of types which must be converted to the backend - // representation before this type can be converted. This is for - // cases like - // type S1 { p *S2 } - // type S2 { s S1 } - // where we can't convert S2 to the backend representation unless we - // have converted S1. - std::vector<Named_type*> dependencies_; - // Whether this type is visible. This is false if this type was - // created because it was referenced by an imported object, but the - // type itself was not exported. This will always be true for types - // created in the current package. - bool is_visible_; - // Whether this type is erroneous. - bool is_error_; - // Whether the current value of named_btype_ is a placeholder for - // which the final size of the type is not known. - bool is_placeholder_; - // Whether this type has been converted to the backend - // representation. Implies that is_placeholder_ is false. - bool is_converted_; - // Whether this is a pointer or function type which refers to the - // type itself. - bool is_circular_; - // Whether this type has been verified. - bool is_verified_; - // In a recursive operation such as has_hidden_fields, this flag is - // used to prevent infinite recursion when a type refers to itself. - // This is mutable because it is always reset to false when the - // function exits. - mutable bool seen_; - // Like seen_, but used only by do_compare_is_identity. - bool seen_in_compare_is_identity_; - // Like seen_, but used only by do_get_backend. - bool seen_in_get_backend_; -}; - -// A forward declaration. This handles a type which has been declared -// but not defined. - -class Forward_declaration_type : public Type -{ - public: - Forward_declaration_type(Named_object* named_object); - - // The named object associated with this type declaration. This - // will be resolved. - Named_object* - named_object(); - - const Named_object* - named_object() const; - - // Return the name of the type. - const std::string& - name() const; - - // Return the type to which this points. Give an error if the type - // has not yet been defined. - Type* - real_type(); - - const Type* - real_type() const; - - // Whether the base type has been defined. - bool - is_defined() const; - - // Add a method to this type. - Named_object* - add_method(const std::string& name, Function*); - - // Add a method declaration to this type. - Named_object* - add_method_declaration(const std::string& name, Package*, Function_type*, - Location); - - protected: - int - do_traverse(Traverse* traverse); - - bool - do_verify(); - - bool - do_has_pointer() const - { return this->real_type()->has_pointer(); } - - bool - do_compare_is_identity(Gogo* gogo) - { return this->real_type()->compare_is_identity(gogo); } - - unsigned int - do_hash_for_method(Gogo* gogo) const - { return this->real_type()->hash_for_method(gogo); } - - Btype* - do_get_backend(Gogo* gogo); - - Expression* - do_type_descriptor(Gogo*, Named_type*); - - void - do_reflection(Gogo*, std::string*) const; - - void - do_mangled_name(Gogo*, std::string* ret) const; - - void - do_export(Export*) const; - - private: - // Issue a warning about a use of an undefined type. - void - warn() const; - - // The type declaration. - Named_object* named_object_; - // Whether we have issued a warning about this type. - mutable bool warned_; -}; - -// The Type_context struct describes what we expect for the type of an -// expression. - -struct Type_context -{ - // The exact type we expect, if known. This may be NULL. - Type* type; - // Whether an abstract type is permitted. - bool may_be_abstract; - - // Constructors. - Type_context() - : type(NULL), may_be_abstract(false) - { } - - Type_context(Type* a_type, bool a_may_be_abstract) - : type(a_type), may_be_abstract(a_may_be_abstract) - { } -}; - -#endif // !defined(GO_TYPES_H) diff --git a/gcc-4.8.1/gcc/go/gofrontend/unsafe.cc b/gcc-4.8.1/gcc/go/gofrontend/unsafe.cc deleted file mode 100644 index e7c61f023..000000000 --- a/gcc-4.8.1/gcc/go/gofrontend/unsafe.cc +++ /dev/null @@ -1,96 +0,0 @@ -// unsafe.cc -- Go frontend builtin unsafe package. - -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "go-system.h" - -#include "go-c.h" -#include "types.h" -#include "gogo.h" - -// Set up the builtin unsafe package. This should probably be driven -// by a table. - -void -Gogo::import_unsafe(const std::string& local_name, bool is_local_name_exported, - Location location) -{ - Location bloc = Linemap::predeclared_location(); - - bool add_to_globals; - Package* package = this->add_imported_package("unsafe", local_name, - is_local_name_exported, - "unsafe", location, - &add_to_globals); - - if (package == NULL) - { - go_assert(saw_errors()); - return; - } - - package->set_location(location); - package->set_is_imported(); - - this->imports_.insert(std::make_pair("unsafe", package)); - - Bindings* bindings = package->bindings(); - - // The type may have already been created by an import. - Named_object* no = package->bindings()->lookup("Pointer"); - if (no == NULL) - { - Type* type = Type::make_pointer_type(Type::make_void_type()); - no = bindings->add_type("Pointer", package, type, - Linemap::unknown_location()); - } - else - { - go_assert(no->package() == package); - go_assert(no->is_type()); - go_assert(no->type_value()->is_unsafe_pointer_type()); - no->type_value()->set_is_visible(); - } - Named_type* pointer_type = no->type_value(); - if (add_to_globals) - this->add_named_type(pointer_type); - - Type* uintptr_type = Type::lookup_integer_type("uintptr"); - - // Sizeof. - Typed_identifier_list* results = new Typed_identifier_list; - results->push_back(Typed_identifier("", uintptr_type, bloc)); - Function_type* fntype = Type::make_function_type(NULL, NULL, results, bloc); - fntype->set_is_builtin(); - no = bindings->add_function_declaration("Sizeof", package, fntype, bloc); - if (add_to_globals) - this->add_named_object(no); - - // Offsetof. - results = new Typed_identifier_list; - results->push_back(Typed_identifier("", uintptr_type, bloc)); - fntype = Type::make_function_type(NULL, NULL, results, bloc); - fntype->set_is_varargs(); - fntype->set_is_builtin(); - no = bindings->add_function_declaration("Offsetof", package, fntype, bloc); - if (add_to_globals) - this->add_named_object(no); - - // Alignof. - results = new Typed_identifier_list; - results->push_back(Typed_identifier("", uintptr_type, bloc)); - fntype = Type::make_function_type(NULL, NULL, results, bloc); - fntype->set_is_varargs(); - fntype->set_is_builtin(); - no = bindings->add_function_declaration("Alignof", package, fntype, bloc); - if (add_to_globals) - this->add_named_object(no); - - if (!this->imported_unsafe_) - { - go_imported_unsafe(); - this->imported_unsafe_ = true; - } -} diff --git a/gcc-4.8.1/gcc/go/gospec.c b/gcc-4.8.1/gcc/go/gospec.c deleted file mode 100644 index 0be7716be..000000000 --- a/gcc-4.8.1/gcc/go/gospec.c +++ /dev/null @@ -1,410 +0,0 @@ -/* gospec.c -- Specific flags and argument handling of the gcc Go front end. - Copyright (C) 2009-2013 Free Software Foundation, Inc. - -This file is part of GCC. - -GCC 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, or (at your option) any later -version. - -GCC 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 GCC; see the file COPYING3. If not see -<http://www.gnu.org/licenses/>. */ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "tm.h" -#include "gcc.h" -#include "opts.h" - -/* This bit is set if we saw a `-xfoo' language specification. */ -#define LANGSPEC (1<<1) -/* This bit is set if they did `-lm' or `-lmath'. */ -#define MATHLIB (1<<2) -/* This bit is set if they did `-lpthread'. */ -#define THREADLIB (1<<3) -/* This bit is set if they did `-lc'. */ -#define WITHLIBC (1<<4) -/* Skip this option. */ -#define SKIPOPT (1<<5) - -#ifndef MATH_LIBRARY -#define MATH_LIBRARY "m" -#endif -#ifndef MATH_LIBRARY_PROFILE -#define MATH_LIBRARY_PROFILE MATH_LIBRARY -#endif - -#define THREAD_LIBRARY "pthread" -#define THREAD_LIBRARY_PROFILE THREAD_LIBRARY - -#define LIBGO "go" -#define LIBGO_PROFILE LIBGO -#define LIBGOBEGIN "gobegin" - -void -lang_specific_driver (struct cl_decoded_option **in_decoded_options, - unsigned int *in_decoded_options_count, - int *in_added_libraries) -{ - unsigned int i, j; - - /* If true, the user gave us the `-p' or `-pg' flag. */ - bool saw_profile_flag = false; - - /* This is a tristate: - -1 means we should not link in libgo - 0 means we should link in libgo if it is needed - 1 means libgo is needed and should be linked in. - 2 means libgo is needed and should be linked statically. */ - int library = 0; - - /* The new argument list will be contained in this. */ - struct cl_decoded_option *new_decoded_options; - - /* "-lm" or "-lmath" if it appears on the command line. */ - const struct cl_decoded_option *saw_math = 0; - - /* "-lpthread" if it appears on the command line. */ - const struct cl_decoded_option *saw_thread = 0; - - /* "-lc" if it appears on the command line. */ - const struct cl_decoded_option *saw_libc = 0; - - /* An array used to flag each argument that needs a bit set for - LANGSPEC, MATHLIB, or WITHLIBC. */ - int *args; - - /* Whether we need the thread library. */ - int need_thread = 0; - - /* By default, we throw on the math library if we have one. */ - int need_math = (MATH_LIBRARY[0] != '\0'); - - /* True if we saw -static. */ - int static_link = 0; - - /* True if we should add -shared-libgcc to the command-line. */ - int shared_libgcc = 1; - - /* The total number of arguments with the new stuff. */ - unsigned int argc; - - /* The argument list. */ - struct cl_decoded_option *decoded_options; - - /* The number of libraries added in. */ - int added_libraries; - - /* The total number of arguments with the new stuff. */ - int num_args = 1; - - /* Whether the -o option was used. */ - bool saw_opt_o = false; - - /* Whether the -c option was used. Also used for -E, -fsyntax-only, - in general anything which implies only compilation and not - linking. */ - bool saw_opt_c = false; - - /* Whether the -S option was used. */ - bool saw_opt_S = false; - - /* The first input file with an extension of .go. */ - const char *first_go_file = NULL; - - argc = *in_decoded_options_count; - decoded_options = *in_decoded_options; - added_libraries = *in_added_libraries; - - args = XCNEWVEC (int, argc); - - for (i = 1; i < argc; i++) - { - const char *arg = decoded_options[i].arg; - - switch (decoded_options[i].opt_index) - { - case OPT_nostdlib: - case OPT_nodefaultlibs: - library = -1; - break; - - case OPT_l: - if (strcmp (arg, MATH_LIBRARY) == 0) - { - args[i] |= MATHLIB; - need_math = 0; - } - else if (strcmp (arg, THREAD_LIBRARY) == 0) - args[i] |= THREADLIB; - else if (strcmp (arg, "c") == 0) - args[i] |= WITHLIBC; - else - /* Unrecognized libraries (e.g. -lfoo) may require libgo. */ - library = (library == 0) ? 1 : library; - break; - - case OPT_pg: - case OPT_p: - saw_profile_flag = true; - break; - - case OPT_x: - if (library == 0 && strcmp (arg, "go") == 0) - library = 1; - break; - - case OPT_Xlinker: - case OPT_Wl_: - /* Arguments that go directly to the linker might be .o files, - or something, and so might cause libgo to be needed. */ - if (library == 0) - library = 1; - break; - - case OPT_c: - case OPT_E: - case OPT_M: - case OPT_MM: - case OPT_fsyntax_only: - /* Don't specify libraries if we won't link, since that would - cause a warning. */ - saw_opt_c = true; - library = -1; - break; - - case OPT_S: - saw_opt_S = true; - library = -1; - break; - - case OPT_o: - saw_opt_o = true; - break; - - case OPT_static: - static_link = 1; - break; - - case OPT_static_libgcc: - shared_libgcc = 0; - break; - - case OPT_static_libgo: - library = library >= 0 ? 2 : library; - args[i] |= SKIPOPT; - break; - - case OPT_SPECIAL_input_file: - if (library == 0) - library = 1; - - if (first_go_file == NULL) - { - int len; - - len = strlen (arg); - if (len > 3 && strcmp (arg + len - 3, ".go") == 0) - first_go_file = arg; - } - - break; - } - } - - /* There's no point adding -shared-libgcc if we don't have a shared - libgcc. */ -#ifndef ENABLE_SHARED_LIBGCC - shared_libgcc = 0; -#endif - - /* Make sure to have room for the trailing NULL argument. */ - num_args = argc + need_math + shared_libgcc + (library > 0) * 5 + 10; - new_decoded_options = XNEWVEC (struct cl_decoded_option, num_args); - - i = 0; - j = 0; - - /* Copy the 0th argument, i.e., the name of the program itself. */ - new_decoded_options[j++] = decoded_options[i++]; - - /* If we are linking, pass -fsplit-stack if it is supported. */ -#ifdef TARGET_CAN_SPLIT_STACK - if (library >= 0) - { - generate_option (OPT_fsplit_stack, NULL, 1, CL_DRIVER, - &new_decoded_options[j]); - j++; - } -#endif - - /* NOTE: We start at 1 now, not 0. */ - while (i < argc) - { - new_decoded_options[j] = decoded_options[i]; - - /* Make sure -lgo is before the math library, since libgo itself - uses those math routines. */ - if (!saw_math && (args[i] & MATHLIB) && library > 0) - { - --j; - saw_math = &decoded_options[i]; - } - - if (!saw_thread && (args[i] & THREADLIB) && library > 0) - { - --j; - saw_thread = &decoded_options[i]; - } - - if (!saw_libc && (args[i] & WITHLIBC) && library > 0) - { - --j; - saw_libc = &decoded_options[i]; - } - - if ((args[i] & SKIPOPT) != 0) - --j; - - i++; - j++; - } - - /* If we didn't see a -o option, add one. This is because we need - the driver to pass all .go files to go1. Without a -o option the - driver will invoke go1 separately for each input file. FIXME: - This should probably use some other interface to force the driver - to set combine_inputs. */ - if (first_go_file != NULL && !saw_opt_o) - { - if (saw_opt_c || saw_opt_S) - { - const char *base; - int baselen; - int alen; - char *out; - - base = lbasename (first_go_file); - baselen = strlen (base) - 3; - alen = baselen + 3; - out = XNEWVEC (char, alen); - memcpy (out, base, baselen); - /* The driver will convert .o to some other suffix (e.g., - .obj) if appropriate. */ - out[baselen] = '.'; - if (saw_opt_S) - out[baselen + 1] = 's'; - else - out[baselen + 1] = 'o'; - out[baselen + 2] = '\0'; - generate_option (OPT_o, out, 1, CL_DRIVER, - &new_decoded_options[j]); - } - else - generate_option (OPT_o, "a.out", 1, CL_DRIVER, - &new_decoded_options[j]); - j++; - } - - /* Add `-lgo' if we haven't already done so. */ - if (library > 0) - { - generate_option (OPT_l, LIBGOBEGIN, 1, CL_DRIVER, - &new_decoded_options[j]); - added_libraries++; - j++; - -#ifdef HAVE_LD_STATIC_DYNAMIC - if (library > 1 && !static_link) - { - generate_option (OPT_Wl_, LD_STATIC_OPTION, 1, CL_DRIVER, - &new_decoded_options[j]); - j++; - } -#endif - - generate_option (OPT_l, saw_profile_flag ? LIBGO_PROFILE : LIBGO, 1, - CL_DRIVER, &new_decoded_options[j]); - added_libraries++; - j++; - -#ifdef HAVE_LD_STATIC_DYNAMIC - if (library > 1 && !static_link) - { - generate_option (OPT_Wl_, LD_DYNAMIC_OPTION, 1, CL_DRIVER, - &new_decoded_options[j]); - j++; - } -#endif - - /* When linking libgo statically we also need to link with the - pthread library. */ - if (library > 1 || static_link) - need_thread = 1; - } - - if (saw_thread) - new_decoded_options[j++] = *saw_thread; - else if (library > 0 && need_thread) - { - generate_option (OPT_l, - (saw_profile_flag - ? THREAD_LIBRARY_PROFILE - : THREAD_LIBRARY), - 1, CL_DRIVER, &new_decoded_options[j]); - added_libraries++; - j++; - } - - if (saw_math) - new_decoded_options[j++] = *saw_math; - else if (library > 0 && need_math) - { - generate_option (OPT_l, - saw_profile_flag ? MATH_LIBRARY_PROFILE : MATH_LIBRARY, - 1, CL_DRIVER, &new_decoded_options[j]); - added_libraries++; - j++; - } - - if (saw_libc) - new_decoded_options[j++] = *saw_libc; - if (shared_libgcc && !static_link) - generate_option (OPT_shared_libgcc, NULL, 1, CL_DRIVER, - &new_decoded_options[j++]); - -#ifdef TARGET_CAN_SPLIT_STACK - /* libgcc wraps pthread_create to support split stack, however, due to - relative ordering of -lpthread and -lgcc, we can't just mark - __real_pthread_create in libgcc as non-weak. But we need to link in - pthread_create from pthread if we are statically linking, so we work- - around by passing -u pthread_create to to the linker. */ - if (static_link) - { - generate_option (OPT_Wl_, "-u,pthread_create", 1, CL_DRIVER, - &new_decoded_options[j]); - j++; - } -#endif - - *in_decoded_options_count = j; - *in_decoded_options = new_decoded_options; - *in_added_libraries = added_libraries; -} - -/* Called before linking. Returns 0 on success and -1 on failure. */ -int lang_specific_pre_link (void) /* Not used for Go. */ -{ - return 0; -} - -/* Number of extra output files that lang_specific_pre_link may generate. */ -int lang_specific_extra_outfiles = 0; /* Not used for Go. */ diff --git a/gcc-4.8.1/gcc/go/lang-specs.h b/gcc-4.8.1/gcc/go/lang-specs.h deleted file mode 100644 index ce1eb9761..000000000 --- a/gcc-4.8.1/gcc/go/lang-specs.h +++ /dev/null @@ -1,25 +0,0 @@ -/* lang-specs.h -- gcc driver specs for Go frontend. - Copyright (C) 2009-2013 Free Software Foundation, Inc. - -This file is part of GCC. - -GCC 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, or (at your option) any later -version. - -GCC 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 GCC; see the file COPYING3. If not see -<http://www.gnu.org/licenses/>. */ - -/* This is the contribution to the `default_compilers' array in gcc.c - for the Go language. */ - -{".go", "@go", 0, 1, 0}, -{"@go", "go1 %i %(cc1_options) %{I*} %{L*} %D %{!fsyntax-only:%(invoke_as)}", - 0, 1, 0}, diff --git a/gcc-4.8.1/gcc/go/lang.opt b/gcc-4.8.1/gcc/go/lang.opt deleted file mode 100644 index f7bd0b96a..000000000 --- a/gcc-4.8.1/gcc/go/lang.opt +++ /dev/null @@ -1,76 +0,0 @@ -; lang.opt -- Options for the gcc Go front end. - -; Copyright (C) 2009-2013 Free Software Foundation, Inc. -; -; This file is part of GCC. -; -; GCC 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, or (at your option) any later -; version. -; -; GCC 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 GCC; see the file COPYING3. If not see -; <http://www.gnu.org/licenses/>. - -; See the GCC internals manual for a description of this file's format. - -; Please try to keep this file in ASCII collating order. - -Language -Go - -I -Go Joined Separate -; Documented in c.opt - -L -Go Joined Separate -; Not documented - -Wall -Go -; Documented in c.opt - -fgo-check-divide-zero -Go Var(go_check_divide_zero) Init(1) -Add explicit checks for division by zero - -fgo-check-divide-overflow -Go Var(go_check_divide_overflow) Init(1) -Add explicit checks for division overflow in INT_MIN / -1 - -fgo-dump- -Go Joined RejectNegative --fgo-dump-<type> Dump Go frontend internal information - -fgo-optimize- -Go Joined RejectNegative --fgo-optimize-<type> Turn on optimization passes in the frontend - -fgo-pkgpath= -Go Joined RejectNegative --fgo-pkgpath=<string> Set Go package path - -fgo-prefix= -Go Joined RejectNegative --fgo-prefix=<string> Set package-specific prefix for exported Go names - -fgo-relative-import-path= -Go Joined RejectNegative --fgo-relative-import-path=<path> Treat a relative import as relative to path - -frequire-return-statement -Go Var(go_require_return_statement) Init(1) Warning -Functions which return values must end with return statements - -o -Go Joined Separate -; Documented in common.opt - -; This comment is to ensure we retain the blank line above. |