Add Go frontend, libgo library, and Go testsuite.
gcc/: * gcc.c (default_compilers): Add entry for ".go". * common.opt: Add -static-libgo as a driver option. * doc/install.texi (Configuration): Mention libgo as an option for --enable-shared. Mention go as an option for --enable-languages. * doc/invoke.texi (Overall Options): Mention .go as a file name suffix. Mention go as a -x option. * doc/frontends.texi (G++ and GCC): Mention Go as a supported language. * doc/sourcebuild.texi (Top Level): Mention libgo. * doc/standards.texi (Standards): Add section on Go language. Move references for other languages into their own section. * doc/contrib.texi (Contributors): Mention that I contributed the Go frontend. gcc/testsuite/: * lib/go.exp: New file. * lib/go-dg.exp: New file. * lib/go-torture.exp: New file. * lib/target-supports.exp (check_compile): Match // Go. From-SVN: r167407
This commit is contained in:
parent
1aa6700378
commit
7a9389330e
|
@ -1,3 +1,19 @@
|
|||
2010-12-02 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* gcc.c (default_compilers): Add entry for ".go".
|
||||
* common.opt: Add -static-libgo as a driver option.
|
||||
* doc/install.texi (Configuration): Mention libgo as an option for
|
||||
--enable-shared. Mention go as an option for --enable-languages.
|
||||
* doc/invoke.texi (Overall Options): Mention .go as a file name
|
||||
suffix. Mention go as a -x option.
|
||||
* doc/frontends.texi (G++ and GCC): Mention Go as a supported
|
||||
language.
|
||||
* doc/sourcebuild.texi (Top Level): Mention libgo.
|
||||
* doc/standards.texi (Standards): Add section on Go language.
|
||||
Move references for other languages into their own section.
|
||||
* doc/contrib.texi (Contributors): Mention that I contributed the
|
||||
Go frontend.
|
||||
|
||||
2010-12-03 Laurynas Biveinis <laurynas.biveinis@gmail.com>
|
||||
|
||||
* tree.h (struct call_expr_arg_iterator_d): Remove GTY tag.
|
||||
|
|
|
@ -2272,6 +2272,10 @@ Driver
|
|||
static-libstdc++
|
||||
Driver
|
||||
|
||||
static-libgo
|
||||
Driver
|
||||
; Documented for Go, but always accepted by driver.
|
||||
|
||||
symbolic
|
||||
Driver
|
||||
|
||||
|
|
|
@ -900,8 +900,8 @@ Jeff Sturm for Java porting help, bug fixes, and encouragement.
|
|||
Shigeya Suzuki for this fixes for the bsdi platforms.
|
||||
|
||||
@item
|
||||
Ian Lance Taylor for his mips16 work, general configury hacking,
|
||||
fixincludes, etc.
|
||||
Ian Lance Taylor for the Go frontend, the initial mips16 and mips64
|
||||
support, general configury hacking, fixincludes, etc.
|
||||
|
||||
@item
|
||||
Holger Teutsch provided the support for the Clipper CPU@.
|
||||
|
|
|
@ -11,13 +11,14 @@
|
|||
@cindex GNU C Compiler
|
||||
@cindex Ada
|
||||
@cindex Fortran
|
||||
@cindex Go
|
||||
@cindex Java
|
||||
@cindex Objective-C
|
||||
@cindex Objective-C++
|
||||
GCC stands for ``GNU Compiler Collection''. GCC is an integrated
|
||||
distribution of compilers for several major programming languages. These
|
||||
languages currently include C, C++, Objective-C, Objective-C++, Java,
|
||||
Fortran, and Ada.
|
||||
Fortran, Ada, and Go.
|
||||
|
||||
The abbreviation @dfn{GCC} has multiple meanings in common use. The
|
||||
current official meaning is ``GNU Compiler Collection'', which refers
|
||||
|
|
|
@ -884,7 +884,7 @@ only for the listed packages. For other packages, only static libraries
|
|||
will be built. Package names currently recognized in the GCC tree are
|
||||
@samp{libgcc} (also known as @samp{gcc}), @samp{libstdc++} (not
|
||||
@samp{libstdc++-v3}), @samp{libffi}, @samp{zlib}, @samp{boehm-gc},
|
||||
@samp{ada}, @samp{libada}, @samp{libjava} and @samp{libobjc}.
|
||||
@samp{ada}, @samp{libada}, @samp{libjava}, @samp{libgo}, and @samp{libobjc}.
|
||||
Note @samp{libiberty} does not support shared libraries at all.
|
||||
|
||||
Use @option{--disable-shared} to build only static libraries. Note that
|
||||
|
@ -1305,15 +1305,12 @@ their runtime libraries should be built. For a list of valid values for
|
|||
grep language= */config-lang.in
|
||||
@end smallexample
|
||||
Currently, you can use any of the following:
|
||||
@code{all}, @code{ada}, @code{c}, @code{c++}, @code{fortran}, @code{java},
|
||||
@code{objc}, @code{obj-c++}.
|
||||
@code{all}, @code{ada}, @code{c}, @code{c++}, @code{fortran},
|
||||
@code{go}, @code{java}, @code{objc}, @code{obj-c++}.
|
||||
Building the Ada compiler has special requirements, see below.
|
||||
If you do not pass this flag, or specify the option @code{all}, then all
|
||||
default languages available in the @file{gcc} sub-tree will be configured.
|
||||
Ada and Objective-C++ are not default languages; the rest are.
|
||||
Re-defining @code{LANGUAGES} when calling @samp{make} @strong{does not}
|
||||
work anymore, as those language sub-directories might not have been
|
||||
configured!
|
||||
Ada, Go and Objective-C++ are not default languages; the rest are.
|
||||
|
||||
@item --enable-stage1-languages=@var{lang1},@var{lang2},@dots{}
|
||||
Specify that a particular subset of compilers and their runtime
|
||||
|
|
|
@ -1070,6 +1070,9 @@ Free form Fortran source code which should not be preprocessed.
|
|||
Free form Fortran source code which must be preprocessed (with the
|
||||
traditional preprocessor).
|
||||
|
||||
@item @var{file}.go
|
||||
Go source code.
|
||||
|
||||
@c FIXME: Descriptions of Java file types.
|
||||
@c @var{file}.java
|
||||
@c @var{file}.class
|
||||
|
@ -1123,6 +1126,7 @@ objective-c++ objective-c++-header objective-c++-cpp-output
|
|||
assembler assembler-with-cpp
|
||||
ada
|
||||
f77 f77-cpp-input f95 f95-cpp-input
|
||||
go
|
||||
java
|
||||
@end smallexample
|
||||
|
||||
|
|
|
@ -81,6 +81,10 @@ The GCC runtime library.
|
|||
@item libgfortran
|
||||
The Fortran runtime library.
|
||||
|
||||
@item libgo
|
||||
The Go runtime library. The bulk of this library is mirrored from the
|
||||
@uref{http://code.google.com/@/p/@/go, master Go repository}.
|
||||
|
||||
@item libgomp
|
||||
The GNU OpenMP runtime library.
|
||||
|
||||
|
|
|
@ -271,6 +271,18 @@ The authoritative manual on Objective-C 2.0 is available from Apple:
|
|||
For more information concerning the history of Objective-C that is
|
||||
available online, see @uref{http://gcc.gnu.org/readings.html}
|
||||
|
||||
@section Go language
|
||||
|
||||
The Go language continues to evolve as of this writing; see the
|
||||
@uref{http://golang.org/@/doc/@/go_spec.html, current language
|
||||
specifications}. At present there are no specific versions of Go, and
|
||||
there is no way to describe the language supported by GCC in terms of
|
||||
a specific version. In general GCC tracks the evolving specification
|
||||
closely, and any given release will support the language as of the
|
||||
date that the release was frozen.
|
||||
|
||||
@section References for other languages
|
||||
|
||||
@xref{Top, GNAT Reference Manual, About This Guide, gnat_rm,
|
||||
GNAT Reference Manual}, for information on standard
|
||||
conformance and compatibility of the Ada compiler.
|
||||
|
|
|
@ -896,6 +896,7 @@ static const struct compiler default_compilers[] =
|
|||
{".p", "#Pascal", 0, 0, 0}, {".pas", "#Pascal", 0, 0, 0},
|
||||
{".java", "#Java", 0, 0, 0}, {".class", "#Java", 0, 0, 0},
|
||||
{".zip", "#Java", 0, 0, 0}, {".jar", "#Java", 0, 0, 0},
|
||||
{".go", "#Go", 0, 1, 0},
|
||||
/* Next come the entries for C. */
|
||||
{".c", "@c", 0, 0, 1},
|
||||
{"@c",
|
||||
|
|
|
@ -0,0 +1,267 @@
|
|||
# Make-lang.in -- Top level -*- makefile -*- fragment for gcc Go frontend.
|
||||
|
||||
# Copyright (C) 2009, 2010 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_LINK='$(SHLIB_LINK)'; \
|
||||
$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(DRIVER_DEFINES) \
|
||||
$(INCLUDES) $(srcdir)/go/gospec.c)
|
||||
|
||||
GCCGO_OBJS = $(GCC_OBJS) gospec.o intl.o prefix.o version.o
|
||||
gccgo$(exeext): $(GCCGO_OBJS) $(EXTRA_GCC_OBJS) $(LIBDEPS)
|
||||
$(LINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ \
|
||||
$(GCCGO_OBJS) $(EXTRA_GCC_OBJS) $(LIBS)
|
||||
|
||||
# Use strict warnings.
|
||||
go-warn = $(STRICT_WARN)
|
||||
|
||||
GO_OBJS = \
|
||||
go/dataflow.o \
|
||||
go/export.o \
|
||||
go/expressions.o \
|
||||
go/go-dump.o \
|
||||
go/go-lang.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/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$(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
|
||||
|
||||
check-go:
|
||||
lang_checks += check-go
|
||||
|
||||
# Install hooks.
|
||||
|
||||
go.install-common: installdirs
|
||||
-rm -f $(DESTDIR)$(bindir)/$(GCCGO_INSTALL_NAME)$(exeext)
|
||||
-rm -f $(DESTDIR)$(bindir)/$(GCCGO_TARGET_INSTALL_NAME)$(exeext)
|
||||
$(INSTALL_PROGRAM) gccgo$(exeext) $(DESTDIR)$(bindir)/$(GCCGO_INSTALL_NAME)$(exeext)
|
||||
if test -f $(DESTDIR)$(bindir)$(GCCGO_TARGET_INSTALL_NAME)$(exeext); then \
|
||||
:; \
|
||||
else \
|
||||
cd $(DESTDIR)$(bindir) && \
|
||||
$(LN) $(GCCGO_INSTALL_NAME)$(exeext) $(GCCGO_TARGET_INSTALL_NAME)$(exeext); \
|
||||
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)
|
||||
|
||||
GO_C_H = go/go-c.h $(MACHMODE_H)
|
||||
GO_LEX_H = go/gofrontend/lex.h go/gofrontend/operator.h
|
||||
GO_PARSE_H = go/gofrontend/parse.h
|
||||
GO_GOGO_H = go/gofrontend/gogo.h
|
||||
GO_TYPES_H = go/gofrontend/types.h
|
||||
GO_STATEMENTS_H = go/gofrontend/statements.h go/gofrontend/operator.h
|
||||
GO_EXPRESSIONS_H = go/gofrontend/expressions.h go/gofrontend/operator.h
|
||||
GO_IMPORT_H = go/gofrontend/import.h go/gofrontend/export.h
|
||||
|
||||
go/go-lang.o: go/go-lang.c $(GO_SYSTEM_H) coretypes.h opts.h $(TREE_H) \
|
||||
$(GIMPLE_H) $(GGC_H) $(TOPLEV_H) debug.h options.h $(FLAGS_H) \
|
||||
convert.h langhooks.h $(LANGHOOKS_DEF_H) $(EXCEPT_H) $(TARGET_H) \
|
||||
$(DIAGNOSTIC_H) $(GO_C_H) gt-go-go-lang.h gtype-go.h
|
||||
|
||||
GOINCLUDES = -I $(srcdir)/go -I $(srcdir)/go/gofrontend
|
||||
|
||||
go/%.o: go/gofrontend/%.cc
|
||||
$(CXX) -c $(GOINCLUDES) $(ALL_CPPFLAGS) $(ALL_CXXFLAGS) $< $(OUTPUT_OPTION)
|
||||
|
||||
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 $(MACHMODE_H) output.h $(TARGET_H) \
|
||||
$(GO_GOGO_H) $(GO_TYPES_H) $(GO_STATEMENTS_H) go/gofrontend/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 $(TM_H) $(TM_P_H) $(GO_C_H) $(GO_GOGO_H) $(GO_TYPES_H) \
|
||||
go/gofrontend/export.h $(GO_IMPORT_H) $(GO_STATEMENTS_H) $(GO_LEX_H) \
|
||||
$(GO_EXPRESSIONS_H)
|
||||
go/go.o: go/gofrontend/go.cc $(GO_SYSTEM_H) $(GO_C_H) $(GO_LEX_H) \
|
||||
$(GO_PARSE_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/gogo-tree.o: go/gofrontend/gogo-tree.cc $(GO_SYSTEM_H) $(TM_H) $(TOPLEV_H) \
|
||||
$(TREE_H) $(GIMPLE_H) tree-iterator.h $(CGRAPH_H) langhooks.h \
|
||||
convert.h output.h $(DIAGNOSTIC_H) $(RTL_H) $(GO_TYPES_H) \
|
||||
$(GO_EXPRESSIONS_H) $(GO_STATEMENTS_H) $(GO_GOGO_H)
|
||||
go/gogo.o: go/gofrontend/gogo.cc $(GO_SYSTEM_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_IMPORT_H) \
|
||||
go/gofrontend/export.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_TYPES_H) go/gofrontend/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/statements.o: go/gofrontend/statements.cc $(GO_SYSTEM_H) intl.h $(TREE_H) \
|
||||
$(GIMPLE_H) convert.h tree-iterator.h $(TREE_FLOW_H) $(REAL_H) \
|
||||
$(GO_C_H) $(GO_TYPES_H) $(GO_EXPRESSIONS_H) $(GO_GOGO_H) \
|
||||
$(GO_STATEMENTS_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/gofrontend/export.h $(GO_IMPORT_H) $(GO_TYPES_H)
|
||||
go/unsafe.o: go/gofrontend/unsafe.cc $(GO_SYSTEM_H) $(GO_TYPES_H) $(GO_GOGO_H)
|
|
@ -0,0 +1,3 @@
|
|||
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.
|
|
@ -0,0 +1,37 @@
|
|||
# config-lang.in -- Top level configure fragment for gcc Go frontend.
|
||||
|
||||
# Copyright (C) 2009, 2010 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"
|
||||
|
||||
# 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"
|
|
@ -0,0 +1,348 @@
|
|||
\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
|
||||
|
||||
@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-vera.
|
||||
* 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 compiling, synonymous with @option{-I}. When linking, specify a
|
||||
library search directory, as with @command{gcc}.
|
||||
|
||||
@item -fgo-prefix=@var{string}
|
||||
@cindex @option{-fgo-prefix}
|
||||
Go permits a single program to include more than one package with the
|
||||
same name. This option is required to make this work with
|
||||
@command{gccgo}. The argument to this option may be any string. Each
|
||||
package with the same name must use a distinct @option{-fgo-prefix}
|
||||
option. The argument is typically the full path under which the
|
||||
package will be installed, as that must obviously be unique.
|
||||
|
||||
@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}.
|
||||
@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{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} or @option{-L} 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{__asm__}
|
||||
Go code can call C functions directly using a Go extension implemented
|
||||
in @command{gccgo}: a function declaration may be followed by
|
||||
@code{__asm__ ("@var{name}")}. For example, here is how the C function
|
||||
@code{open} can be declared in Go:
|
||||
|
||||
@smallexample
|
||||
func c_open(name *byte, mode int, perm int) int __asm__ ("open");
|
||||
@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}
|
||||
extension similar to the @command{gccgo} extension.
|
||||
|
||||
@smallexample
|
||||
extern int go_function(int) __asm__ ("myprefix.mypackage.Function");
|
||||
@end smallexample
|
||||
|
||||
@node Index
|
||||
@unnumbered Index
|
||||
|
||||
@printindex cp
|
||||
|
||||
@bye
|
|
@ -0,0 +1,66 @@
|
|||
/* go-c.h -- Header file for go frontend gcc C interface.
|
||||
Copyright (C) 2009, 2010 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
|
||||
|
||||
#ifdef ENABLE_BUILD_WITH_CXX
|
||||
#define GO_EXTERN_C
|
||||
#else
|
||||
#define GO_EXTERN_C extern "C"
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus) && !defined(ENABLE_BUILD_WITH_CXX)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include "machmode.h"
|
||||
|
||||
/* Functions defined in the Go frontend proper called by the GCC
|
||||
interface. */
|
||||
|
||||
extern int go_enable_dump (const char*);
|
||||
extern void go_set_prefix (const char*);
|
||||
|
||||
extern void go_add_search_path (const char*);
|
||||
|
||||
extern void go_create_gogo (int int_type_size, int float_type_size,
|
||||
int pointer_size);
|
||||
|
||||
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*);
|
||||
|
||||
#if defined(__cplusplus) && !defined(ENABLE_BUILD_WITH_CXX)
|
||||
} /* End extern "C". */
|
||||
#endif
|
||||
|
||||
#endif /* !defined(GO_GO_C_H) */
|
|
@ -0,0 +1,404 @@
|
|||
/* go-lang.c -- Go frontend gcc interface.
|
||||
Copyright (C) 2009, 2010 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 <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(()) 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 ("(union lang_tree_node *) TREE_CHAIN (&%h.generic)")))
|
||||
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;
|
||||
};
|
||||
|
||||
/* Language hooks. */
|
||||
|
||||
static bool
|
||||
go_langhook_init (void)
|
||||
{
|
||||
build_common_tree_nodes (false);
|
||||
|
||||
/* The sizetype may be "unsigned long" or "unsigned long long". */
|
||||
if (TYPE_MODE (long_unsigned_type_node) == ptr_mode)
|
||||
size_type_node = long_unsigned_type_node;
|
||||
else if (TYPE_MODE (long_long_unsigned_type_node) == ptr_mode)
|
||||
size_type_node = long_long_unsigned_type_node;
|
||||
else
|
||||
size_type_node = long_unsigned_type_node;
|
||||
set_sizetype (size_type_node);
|
||||
|
||||
build_common_tree_nodes_2 (0);
|
||||
|
||||
/* 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, FLOAT_TYPE_SIZE, POINTER_SIZE);
|
||||
|
||||
build_common_builtin_nodes ();
|
||||
|
||||
/* I don't know why this is not done by any of the above. */
|
||||
void_list_node = build_tree_list (NULL_TREE, void_type_node);
|
||||
|
||||
/* 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 (128);
|
||||
|
||||
/* 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;
|
||||
|
||||
/* By default assume that floating point math does not trap. */
|
||||
opts->x_flag_trapping_math = 0;
|
||||
|
||||
/* We turn on stack splitting if we can. */
|
||||
if (targetm.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;
|
||||
}
|
||||
|
||||
/* 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:
|
||||
case OPT_L:
|
||||
/* For the compiler, we currently handle -I and -L exactly the
|
||||
same way: they give us a directory to search for import
|
||||
statements. */
|
||||
go_add_search_path (arg);
|
||||
break;
|
||||
|
||||
case OPT_fgo_dump_:
|
||||
ret = go_enable_dump (arg) ? true : false;
|
||||
break;
|
||||
|
||||
case OPT_fgo_prefix_:
|
||||
go_set_prefix (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)
|
||||
{
|
||||
gcc_assert (num_in_fnames > 0);
|
||||
|
||||
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)
|
||||
{
|
||||
return go_type_for_mode (mode, unsignedp);
|
||||
}
|
||||
|
||||
/* Record a builtin function. We just ignore builtin functions. */
|
||||
|
||||
static tree
|
||||
go_langhook_builtin_function (tree decl)
|
||||
{
|
||||
return decl;
|
||||
}
|
||||
|
||||
static int
|
||||
go_langhook_global_bindings_p (void)
|
||||
{
|
||||
return current_function_decl == NULL ? 1 : 0;
|
||||
}
|
||||
|
||||
/* 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"
|
|
@ -0,0 +1,153 @@
|
|||
// go-system.h -- Go frontend inclusion of gcc header files -*- C++ -*-
|
||||
// Copyright (C) 2009, 2010 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>
|
||||
|
||||
// Some versions of gmp.h assume that #include <iostream> will define
|
||||
// std::FILE. This is not true with libstdc++ 4.3 and later. This is
|
||||
// fixed in GMP 4.3, but at this point we don't know which version of
|
||||
// GMP is in use. Since the top level configure script accepts GMP
|
||||
// 4.2, at least for now we #include <cstdio> to ensure that GMP 4.2
|
||||
// will work. FIXME: This can be removed when we require GMP 4.3 or
|
||||
// later.
|
||||
#include <cstdio>
|
||||
|
||||
#ifndef ENABLE_BUILD_WITH_CXX
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include "system.h"
|
||||
#include "ansidecl.h"
|
||||
#include "coretypes.h"
|
||||
|
||||
#include "diagnostic-core.h" /* For error_at and friends. */
|
||||
#include "input.h" /* For source_location. */
|
||||
|
||||
#ifndef ENABLE_BUILD_WITH_CXX
|
||||
} // End extern "C"
|
||||
#endif
|
||||
|
||||
#endif // !defined(GO_SYSTEM_H)
|
|
@ -0,0 +1,42 @@
|
|||
// 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.
|
||||
//
|
||||
// Subject to the terms and conditions of this License, 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, and
|
||||
// otherwise transfer this implementation of Go, where such license
|
||||
// applies only to those patent claims licensable by Google that are
|
||||
// necessarily infringed by use of this implementation of Go. If You
|
||||
// institute patent litigation against any entity (including a
|
||||
// cross-claim or counterclaim in a lawsuit) alleging that this
|
||||
// implementation of Go or a Contribution incorporated within this
|
||||
// implementation of Go constitutes direct or contributory patent
|
||||
// infringement, then any patent licenses granted to You under this
|
||||
// License for this implementation of Go shall terminate as of the date
|
||||
// such litigation is filed.
|
|
@ -0,0 +1,57 @@
|
|||
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.
|
||||
|
||||
* Use of gcc_assert and gcc_unreachable.
|
||||
|
||||
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 .
|
||||
|
||||
Changes to these files require a copyright assignment to Google. This
|
||||
is required to permit the changes to be copied to the gcc repository,
|
||||
as Google has a copyright assignment with the Free Software
|
||||
Foundation.
|
||||
|
||||
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.
|
|
@ -0,0 +1,278 @@
|
|||
// 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();
|
||||
gcc_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);
|
||||
gcc_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.
|
||||
source_location loc1 = no1->location();
|
||||
source_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.
|
||||
gcc_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;
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
// 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)
|
|
@ -0,0 +1,441 @@
|
|||
// 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"
|
||||
|
||||
#ifndef ENABLE_BUILD_WITH_CXX
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include "machmode.h"
|
||||
#include "output.h"
|
||||
#include "target.h"
|
||||
|
||||
#ifndef ENABLE_BUILD_WITH_CXX
|
||||
}
|
||||
#endif
|
||||
|
||||
#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)
|
||||
{
|
||||
}
|
||||
|
||||
// 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& unique_prefix,
|
||||
int package_priority,
|
||||
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 unique prefix. This prefix is used for all global symbols.
|
||||
this->write_c_string("prefix ");
|
||||
this->write_string(unique_prefix);
|
||||
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_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);
|
||||
}
|
||||
|
||||
// Write out the import control variables 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("import");
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
// 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;
|
||||
gcc_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.
|
||||
gcc_assert(named_type->location() != BUILTINS_LOCATION
|
||||
|| (named_type->named_object()->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->unique_prefix();
|
||||
s += '.';
|
||||
s += package->name();
|
||||
s += '.';
|
||||
}
|
||||
s += named_object->name();
|
||||
s += "\" ";
|
||||
this->write_string(s);
|
||||
|
||||
// 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, "float", BUILTIN_FLOAT);
|
||||
this->register_builtin_type(gogo, "complex", BUILTIN_COMPLEX);
|
||||
this->register_builtin_type(gogo, "bool", BUILTIN_BOOL);
|
||||
this->register_builtin_type(gogo, "string", BUILTIN_STRING);
|
||||
}
|
||||
|
||||
// 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);
|
||||
gcc_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));
|
||||
gcc_assert(ins.second);
|
||||
|
||||
// We also insert the underlying type. We can see the underlying
|
||||
// type at least for string and bool.
|
||||
Type* real_type = named_object->type_value()->real_type();
|
||||
ins = this->type_refs_.insert(std::make_pair(real_type, code));
|
||||
gcc_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()
|
||||
: section_(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
// Write data to a section.
|
||||
|
||||
void
|
||||
Stream_to_section::do_write(const char* bytes, size_t length)
|
||||
{
|
||||
section* sec = (section*) this->section_;
|
||||
if (sec == NULL)
|
||||
{
|
||||
gcc_assert(targetm.have_named_sections);
|
||||
|
||||
sec = get_section(".go_export", SECTION_DEBUG, NULL);
|
||||
this->section_ = (void*) sec;
|
||||
}
|
||||
|
||||
switch_to_section(sec);
|
||||
assemble_string(bytes, length);
|
||||
}
|
|
@ -0,0 +1,191 @@
|
|||
// 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
|
||||
|
||||
struct sha1_ctx;
|
||||
class Gogo;
|
||||
class Import_init;
|
||||
class Bindings;
|
||||
class Type;
|
||||
|
||||
// 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_FLOAT = -14,
|
||||
BUILTIN_BOOL = -15,
|
||||
BUILTIN_STRING = -16,
|
||||
BUILTIN_COMPLEX64 = -17,
|
||||
BUILTIN_COMPLEX128 = -18,
|
||||
BUILTIN_COMPLEX = -19,
|
||||
|
||||
SMALLEST_BUILTIN_CODE = -19
|
||||
};
|
||||
|
||||
// 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:
|
||||
// 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.
|
||||
void
|
||||
write_string(const std::string& s)
|
||||
{ this->write_and_sum_bytes(s.data(), s.length()); }
|
||||
|
||||
// Write a nul terminated string.
|
||||
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.
|
||||
// UNIQUE_PREFIX is a prefix for all global symbols.
|
||||
// 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& unique_prefix,
|
||||
int package_priority,
|
||||
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 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 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_;
|
||||
};
|
||||
|
||||
// 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);
|
||||
|
||||
private:
|
||||
// The section we are writing to; this is really union section
|
||||
// defined in output.h.
|
||||
void* section_;
|
||||
};
|
||||
|
||||
#endif // !defined(GO_EXPORT_H)
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,53 @@
|
|||
// 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;
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
// 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)
|
|
@ -0,0 +1,153 @@
|
|||
// 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 "gogo.h"
|
||||
|
||||
// The unique prefix to use for exported symbols. This is set during
|
||||
// option processing.
|
||||
|
||||
static std::string unique_prefix;
|
||||
|
||||
// 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 float_type_size, int pointer_size)
|
||||
{
|
||||
gcc_assert(::gogo == NULL);
|
||||
::gogo = new Gogo(int_type_size, float_type_size, pointer_size);
|
||||
if (!unique_prefix.empty())
|
||||
::gogo->set_unique_prefix(unique_prefix);
|
||||
}
|
||||
|
||||
// Set the unique prefix we use for exported symbols.
|
||||
|
||||
GO_EXTERN_C
|
||||
void
|
||||
go_set_prefix(const char* arg)
|
||||
{
|
||||
unique_prefix = arg;
|
||||
for (size_t i = 0; i < unique_prefix.length(); ++i)
|
||||
{
|
||||
char c = unique_prefix[i];
|
||||
if ((c >= 'a' && c <= 'z')
|
||||
|| (c >= 'A' && c <= 'Z')
|
||||
|| (c >= '0' && c <= '9')
|
||||
|| c == '_')
|
||||
;
|
||||
else
|
||||
unique_prefix[i] = '_';
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
gcc_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);
|
||||
|
||||
Parse parse(&lexer, ::gogo);
|
||||
parse.program();
|
||||
|
||||
if (strcmp(filename, "-") != 0)
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
::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();
|
||||
|
||||
// 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();
|
||||
|
||||
// Build required interface method tables.
|
||||
::gogo->build_interface_method_tables();
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,661 @@
|
|||
// 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, source_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.
|
||||
source_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.
|
||||
source_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* buf = new char[size];
|
||||
if (::read(this->fd_, buf, size) != size)
|
||||
{
|
||||
error_at(this->location_, "%s: could not read extended names",
|
||||
filename.c_str());
|
||||
delete buf;
|
||||
return false;
|
||||
}
|
||||
this->extended_names_.assign(buf, size);
|
||||
delete buf;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
*nested_off = 0;
|
||||
}
|
||||
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);
|
||||
if (nested_off != NULL)
|
||||
*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,
|
||||
source_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;
|
||||
}
|
|
@ -0,0 +1,892 @@
|
|||
// 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 "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));
|
||||
}
|
||||
|
||||
// The name used for parameters, receivers, and results in imported
|
||||
// function types.
|
||||
|
||||
const char* const Import::import_marker = "*imported*";
|
||||
|
||||
// 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, we use the search path
|
||||
// provided by -I and -L options.
|
||||
|
||||
// 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, source_location location)
|
||||
{
|
||||
if (!IS_ABSOLUTE_PATH(filename))
|
||||
{
|
||||
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 += filename;
|
||||
Stream* s = Import::try_package_in_directory(indir, location);
|
||||
if (s != NULL)
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
Stream* s = Import::try_package_in_directory(filename, 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,
|
||||
source_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,
|
||||
source_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,
|
||||
source_location location)
|
||||
{
|
||||
const char* errmsg;
|
||||
int err;
|
||||
simple_object_read* sobj = simple_object_start_read(fd, offset,
|
||||
"__GNU_GO",
|
||||
&errmsg, &err);
|
||||
if (sobj == NULL)
|
||||
return NULL;
|
||||
|
||||
off_t sec_offset;
|
||||
off_t sec_length;
|
||||
int found = simple_object_find_section(sobj, ".go_export", &sec_offset,
|
||||
&sec_length, &errmsg, &err);
|
||||
|
||||
simple_object_release_read(sobj);
|
||||
|
||||
if (!found)
|
||||
return NULL;
|
||||
|
||||
if (lseek(fd, offset + sec_offset, SEEK_SET) < 0)
|
||||
{
|
||||
error_at(location, "lseek %s failed: %m", filename.c_str());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char* buf = new char[sec_length];
|
||||
ssize_t c = read(fd, buf, sec_length);
|
||||
if (c < 0)
|
||||
{
|
||||
error_at(location, "read %s failed: %m", filename.c_str());
|
||||
return NULL;
|
||||
}
|
||||
if (c < sec_length)
|
||||
{
|
||||
error_at(location, "%s: short read", filename.c_str());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return new Stream_from_buffer(buf, sec_length);
|
||||
}
|
||||
|
||||
// Class Import.
|
||||
|
||||
// Construct an Import object. We make the builtin_types_ vector
|
||||
// large enough to hold all the builtin types.
|
||||
|
||||
Import::Import(Stream* stream, source_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");
|
||||
|
||||
this->require_c_string("prefix ");
|
||||
std::string unique_prefix = this->read_identifier();
|
||||
this->require_c_string(";\n");
|
||||
|
||||
this->package_ = gogo->add_imported_package(package_name, local_name,
|
||||
is_local_name_exported,
|
||||
unique_prefix,
|
||||
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");
|
||||
|
||||
if (stream->match_c_string("import "))
|
||||
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 the list of import control functions.
|
||||
|
||||
void
|
||||
Import::read_import_init_fns(Gogo* gogo)
|
||||
{
|
||||
this->require_c_string("import");
|
||||
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();
|
||||
|
||||
source_location loc = this->location_;
|
||||
Named_object* no;
|
||||
if (fntype->is_method())
|
||||
{
|
||||
Type* rtype = receiver->type()->deref();
|
||||
if (rtype->is_error_type())
|
||||
return NULL;
|
||||
Named_type* named_rtype = rtype->named_type();
|
||||
gcc_assert(named_rtype != NULL);
|
||||
no = named_rtype->add_method_declaration(name, package, fntype, loc);
|
||||
}
|
||||
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 current package, the name will be
|
||||
// .PREFIX.PACKAGE.NAME or simply NAME with no dots. Otherwise, a
|
||||
// non-hidden symbol will be PREFIX.PACKAGE.NAME and a hidden symbol
|
||||
// will be .PREFIX.PACKAGE.NAME.
|
||||
std::string package_name;
|
||||
std::string unique_prefix;
|
||||
if (type_name.find('.') != std::string::npos)
|
||||
{
|
||||
bool is_hidden = false;
|
||||
size_t start = 0;
|
||||
if (type_name[0] == '.')
|
||||
{
|
||||
++start;
|
||||
is_hidden = true;
|
||||
}
|
||||
size_t dot1 = type_name.find('.', start);
|
||||
size_t dot2;
|
||||
if (dot1 == std::string::npos)
|
||||
dot2 = std::string::npos;
|
||||
else
|
||||
dot2 = type_name.find('.', dot1 + 1);
|
||||
if (dot1 == std::string::npos || dot2 == std::string::npos)
|
||||
{
|
||||
error_at(this->location_,
|
||||
("error at import data at %d: missing dot in type name"),
|
||||
stream->pos());
|
||||
stream->set_saw_error();
|
||||
}
|
||||
else
|
||||
{
|
||||
unique_prefix = type_name.substr(start, dot1 - start);
|
||||
package_name = type_name.substr(dot1 + 1, dot2 - (dot1 + 1));
|
||||
}
|
||||
if (!is_hidden)
|
||||
type_name.erase(0, dot2 + 1);
|
||||
}
|
||||
|
||||
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 (package_name.empty())
|
||||
package = this->package_;
|
||||
else
|
||||
package = this->gogo_->register_package(package_name, unique_prefix,
|
||||
UNKNOWN_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",
|
||||
Gogo::message_name(package->name()).c_str(),
|
||||
Gogo::message_name(type_name).c_str());
|
||||
stream->set_saw_error();
|
||||
return Type::make_error_type();
|
||||
}
|
||||
else
|
||||
gcc_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
|
||||
{
|
||||
gcc_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();
|
||||
|
||||
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 methds yet, which means
|
||||
// that we can nt 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, "float", BUILTIN_FLOAT);
|
||||
this->register_builtin_type(gogo, "complex", BUILTIN_COMPLEX);
|
||||
this->register_builtin_type(gogo, "bool", BUILTIN_BOOL);
|
||||
this->register_builtin_type(gogo, "string", BUILTIN_STRING);
|
||||
}
|
||||
|
||||
// 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);
|
||||
gcc_assert(named_object != NULL && named_object->is_type());
|
||||
int index = - static_cast<int>(code);
|
||||
gcc_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;
|
||||
}
|
||||
|
||||
// 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(source_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.
|
||||
gcc_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();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,351 @@
|
|||
// 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"
|
||||
|
||||
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(source_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(source_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.
|
||||
static Stream*
|
||||
open_package(const std::string& filename, source_location location);
|
||||
|
||||
// Constructor.
|
||||
Import(Stream*, source_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.
|
||||
source_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 type.
|
||||
Type*
|
||||
read_type();
|
||||
|
||||
// The name used for parameters, receivers, and results in imported
|
||||
// function types.
|
||||
static const char* const import_marker;
|
||||
|
||||
private:
|
||||
static Stream*
|
||||
try_package_in_directory(const std::string&, source_location);
|
||||
|
||||
static int
|
||||
try_suffixes(std::string*);
|
||||
|
||||
static Stream*
|
||||
find_export_data(const std::string& filename, int fd, source_location);
|
||||
|
||||
static Stream*
|
||||
find_object_export_data(const std::string& filename, int fd,
|
||||
off_t offset, source_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,
|
||||
source_location);
|
||||
|
||||
// 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.
|
||||
source_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 an allocated buffer.
|
||||
|
||||
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()
|
||||
{ delete[] 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)
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,446 @@
|
|||
// 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 <gmp.h>
|
||||
#include <mpfr.h>
|
||||
|
||||
#include "operator.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 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(source_location location)
|
||||
{ return Token(TOKEN_INVALID, location); }
|
||||
|
||||
// Make a token representing end of file.
|
||||
static Token
|
||||
make_eof_token(source_location location)
|
||||
{ return Token(TOKEN_EOF, location); }
|
||||
|
||||
// Make a keyword token.
|
||||
static Token
|
||||
make_keyword_token(Keyword keyword, source_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,
|
||||
source_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, source_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, source_location location)
|
||||
{
|
||||
Token tok(TOKEN_OPERATOR, location);
|
||||
tok.u_.op = op;
|
||||
return tok;
|
||||
}
|
||||
|
||||
// Make an integer token.
|
||||
static Token
|
||||
make_integer_token(mpz_t val, source_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, source_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, source_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.
|
||||
source_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
|
||||
{
|
||||
gcc_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
|
||||
{
|
||||
gcc_assert(this->classification_ == TOKEN_IDENTIFIER);
|
||||
return *this->u_.identifier_value.name;
|
||||
}
|
||||
|
||||
// Return whether the identifier is exported.
|
||||
bool
|
||||
is_identifier_exported() const
|
||||
{
|
||||
gcc_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
|
||||
{
|
||||
gcc_assert(this->classification_ == TOKEN_STRING);
|
||||
return *this->u_.string_value;
|
||||
}
|
||||
|
||||
// Return the value of an integer.
|
||||
const mpz_t*
|
||||
integer_value() const
|
||||
{
|
||||
gcc_assert(this->classification_ == TOKEN_INTEGER);
|
||||
return &this->u_.integer_value;
|
||||
}
|
||||
|
||||
// Return the value of a float.
|
||||
const mpfr_t*
|
||||
float_value() const
|
||||
{
|
||||
gcc_assert(this->classification_ == TOKEN_FLOAT);
|
||||
return &this->u_.float_value;
|
||||
}
|
||||
|
||||
// Return the value of an imaginary number.
|
||||
const mpfr_t*
|
||||
imaginary_value() const
|
||||
{
|
||||
gcc_assert(this->classification_ == TOKEN_IMAGINARY);
|
||||
return &this->u_.float_value;
|
||||
}
|
||||
|
||||
// Return the operator value for an operator token.
|
||||
Operator
|
||||
op() const
|
||||
{
|
||||
gcc_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, source_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_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.
|
||||
source_location location_;
|
||||
};
|
||||
|
||||
// The lexer itself.
|
||||
|
||||
class Lex
|
||||
{
|
||||
public:
|
||||
Lex(const char* input_file_name, FILE* input_file);
|
||||
|
||||
~Lex();
|
||||
|
||||
// Return the next token.
|
||||
Token
|
||||
next_token();
|
||||
|
||||
// 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);
|
||||
|
||||
// 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,
|
||||
source_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);
|
||||
|
||||
private:
|
||||
ssize_t
|
||||
get_line();
|
||||
|
||||
bool
|
||||
require_line();
|
||||
|
||||
// The current location.
|
||||
source_location
|
||||
location() const;
|
||||
|
||||
// A position CHARS column positions before the current location.
|
||||
source_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();
|
||||
|
||||
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 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_;
|
||||
};
|
||||
|
||||
#endif // !defined(GO_LEX_H)
|
|
@ -0,0 +1,66 @@
|
|||
// 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)
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,307 @@
|
|||
// 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 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_CHANOP,
|
||||
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.
|
||||
source_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;
|
||||
|
||||
// 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.
|
||||
source_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*, const Label*> > Bc_stack;
|
||||
|
||||
// Parser nonterminals.
|
||||
void identifier_list(Typed_identifier_list*);
|
||||
Expression_list* expression_list(Expression*, bool may_be_sink);
|
||||
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();
|
||||
Function_type* signature(Typed_identifier*, source_location);
|
||||
Typed_identifier_list* parameters(bool* is_varargs);
|
||||
Typed_identifier_list* parameter_list(bool* is_varargs);
|
||||
void parameter_decl(bool, Typed_identifier_list*, bool*, bool*);
|
||||
Typed_identifier_list* result();
|
||||
source_location block();
|
||||
Type* interface_type();
|
||||
bool 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, source_location);
|
||||
bool init_vars_from_call(const Typed_identifier_list*, Type*, Expression*,
|
||||
bool is_coloneq, source_location);
|
||||
bool init_vars_from_map(const Typed_identifier_list*, Type*, Expression*,
|
||||
bool is_coloneq, source_location);
|
||||
bool init_vars_from_receive(const Typed_identifier_list*, Type*,
|
||||
Expression*, bool is_coloneq, source_location);
|
||||
bool init_vars_from_type_guard(const Typed_identifier_list*, Type*,
|
||||
Expression*, bool is_coloneq,
|
||||
source_location);
|
||||
Named_object* init_var(const Typed_identifier&, Type*, Expression*,
|
||||
bool is_coloneq, bool type_from_init, bool* is_new);
|
||||
void simple_var_decl_or_assignment(const std::string&, source_location,
|
||||
Range_clause*, Type_switch*);
|
||||
void function_decl();
|
||||
Typed_identifier* receiver();
|
||||
Expression* operand(bool may_be_sink);
|
||||
Expression* enclosing_var_reference(Named_object*, Named_object*,
|
||||
source_location);
|
||||
Expression* composite_lit(Type*, int depth, source_location);
|
||||
Expression* function_lit();
|
||||
Expression* create_closure(Named_object* function, Enclosing_vars*,
|
||||
source_location);
|
||||
Expression* primary_expr(bool may_be_sink, bool may_be_composite_lit,
|
||||
bool* is_type_switch);
|
||||
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 expression_may_start_here();
|
||||
Expression* unary_expr(bool may_be_sink, bool may_be_composite_lit,
|
||||
bool* is_type_switch);
|
||||
Expression* qualified_expr(Expression*, source_location);
|
||||
Expression* id_to_expression(const std::string&, source_location);
|
||||
void statement(const Label*);
|
||||
bool statement_may_start_here();
|
||||
void labeled_stmt(const std::string&, source_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 inc_dec_stat(Expression*);
|
||||
void assignment(Expression*, Range_clause*);
|
||||
void tuple_assignment(Expression_list*, Range_clause*);
|
||||
void send();
|
||||
void go_or_defer_stat();
|
||||
void return_stat();
|
||||
void if_stat();
|
||||
void switch_stat(const Label*);
|
||||
Statement* expr_switch_body(const Label*, Expression*, source_location);
|
||||
void expr_case_clause(Case_clauses*);
|
||||
Expression_list* expr_switch_case(bool*);
|
||||
Statement* type_switch_body(const Label*, const Type_switch&,
|
||||
source_location);
|
||||
void type_case_clause(Named_object*, Type_case_clauses*);
|
||||
void type_switch_case(std::vector<Type*>*, bool*);
|
||||
void select_stat(const Label*);
|
||||
void comm_clause(Select_clauses*);
|
||||
bool comm_case(bool*, Expression**, Expression**, std::string*, bool*);
|
||||
bool send_or_recv_expr(bool*, Expression**, Expression**, std::string*);
|
||||
void for_stat(const 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*, const Label*);
|
||||
void push_continue_statement(Statement*, const 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;
|
||||
|
||||
// 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_;
|
||||
// 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_;
|
||||
};
|
||||
|
||||
|
||||
#endif // !defined(GO_PARSE_H)
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,134 @@
|
|||
// 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 "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,
|
||||
source_location location)
|
||||
{
|
||||
location_t bloc = BUILTINS_LOCATION;
|
||||
|
||||
bool add_to_globals;
|
||||
Package* package = this->add_imported_package("unsafe", local_name,
|
||||
is_local_name_exported,
|
||||
"libgo_unsafe",
|
||||
location, &add_to_globals);
|
||||
package->set_is_imported();
|
||||
|
||||
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, UNKNOWN_LOCATION);
|
||||
}
|
||||
else
|
||||
{
|
||||
gcc_assert(no->package() == package);
|
||||
gcc_assert(no->is_type());
|
||||
gcc_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* int_type = this->lookup_global("int")->type_value();
|
||||
|
||||
// Sizeof.
|
||||
Typed_identifier_list* results = new Typed_identifier_list;
|
||||
results->push_back(Typed_identifier("", int_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("", int_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("", int_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);
|
||||
|
||||
// Typeof.
|
||||
Type* empty_interface = Type::make_interface_type(NULL, bloc);
|
||||
Typed_identifier_list* parameters = new Typed_identifier_list;
|
||||
parameters->push_back(Typed_identifier("i", empty_interface, bloc));
|
||||
results = new Typed_identifier_list;
|
||||
results->push_back(Typed_identifier("", empty_interface, bloc));
|
||||
fntype = Type::make_function_type(NULL, parameters, results, bloc);
|
||||
no = bindings->add_function_declaration("Typeof", package, fntype, bloc);
|
||||
if (add_to_globals)
|
||||
this->add_named_object(no);
|
||||
|
||||
// Reflect.
|
||||
parameters = new Typed_identifier_list;
|
||||
parameters->push_back(Typed_identifier("it", empty_interface, bloc));
|
||||
results = new Typed_identifier_list;
|
||||
results->push_back(Typed_identifier("", empty_interface, bloc));
|
||||
results->push_back(Typed_identifier("", pointer_type, bloc));
|
||||
fntype = Type::make_function_type(NULL, parameters, results, bloc);
|
||||
no = bindings->add_function_declaration("Reflect", package, fntype, bloc);
|
||||
if (add_to_globals)
|
||||
this->add_named_object(no);
|
||||
|
||||
// Unreflect.
|
||||
parameters = new Typed_identifier_list;
|
||||
parameters->push_back(Typed_identifier("typ", empty_interface, bloc));
|
||||
parameters->push_back(Typed_identifier("addr", pointer_type, bloc));
|
||||
results = new Typed_identifier_list;
|
||||
results->push_back(Typed_identifier("", empty_interface, bloc));
|
||||
fntype = Type::make_function_type(NULL, parameters, results, bloc);
|
||||
no = bindings->add_function_declaration("Unreflect", package, fntype, bloc);
|
||||
if (add_to_globals)
|
||||
this->add_named_object(no);
|
||||
|
||||
// New.
|
||||
parameters = new Typed_identifier_list;
|
||||
parameters->push_back(Typed_identifier("typ", empty_interface, bloc));
|
||||
results = new Typed_identifier_list;
|
||||
results->push_back(Typed_identifier("", pointer_type, bloc));
|
||||
fntype = Type::make_function_type(NULL, parameters, results, bloc);
|
||||
no = bindings->add_function_declaration("New", package, fntype, bloc);
|
||||
if (add_to_globals)
|
||||
this->add_named_object(no);
|
||||
|
||||
// NewArray.
|
||||
parameters = new Typed_identifier_list;
|
||||
parameters->push_back(Typed_identifier("typ", empty_interface, bloc));
|
||||
parameters->push_back(Typed_identifier("n", int_type, bloc));
|
||||
results = new Typed_identifier_list;
|
||||
results->push_back(Typed_identifier("", pointer_type, bloc));
|
||||
fntype = Type::make_function_type(NULL, parameters, results, bloc);
|
||||
no = bindings->add_function_declaration("NewArray", package, fntype, bloc);
|
||||
if (add_to_globals)
|
||||
this->add_named_object(no);
|
||||
|
||||
this->imported_unsafe_ = true;
|
||||
}
|
|
@ -0,0 +1,327 @@
|
|||
/* gospec.c -- Specific flags and argument handling of the gcc Go front end.
|
||||
Copyright (C) 2009, 2010 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;
|
||||
|
||||
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_S:
|
||||
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. */
|
||||
library = -1;
|
||||
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;
|
||||
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 + 5;
|
||||
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++;
|
||||
}
|
||||
|
||||
/* 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_, "-Bstatic", 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_, "-Bdynamic", 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++]);
|
||||
|
||||
*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. */
|
|
@ -0,0 +1,25 @@
|
|||
/* lang-specs.h -- gcc driver specs for Go frontend.
|
||||
Copyright (C) 2009, 2010 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},
|
|
@ -0,0 +1,56 @@
|
|||
; lang.opt -- Options for the gcc Go front end.
|
||||
|
||||
; Copyright (C) 2009, 2010 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-dump-
|
||||
Go Joined RejectNegative
|
||||
-fgo-dump-<type> Dump Go frontend internal information
|
||||
|
||||
fgo-prefix=
|
||||
Go Joined RejectNegative
|
||||
-fgo-prefix=<string> Set package-specific prefix for exported Go names
|
||||
|
||||
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.
|
|
@ -1,4 +1,11 @@
|
|||
2010-11-02 Eric Botcazou <ebotcazou@adacore.com>
|
||||
2010-12-02 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* lib/go.exp: New file.
|
||||
* lib/go-dg.exp: New file.
|
||||
* lib/go-torture.exp: New file.
|
||||
* lib/target-supports.exp (check_compile): Match // Go.
|
||||
|
||||
2010-12-02 Eric Botcazou <ebotcazou@adacore.com>
|
||||
|
||||
* gcc.dg/pr46685.c: New test.
|
||||
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
# Copyright (C) 2009 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GCC; see the file COPYING3. If not see
|
||||
# <http://www.gnu.org/licenses/>.
|
||||
|
||||
# GCC testsuite that uses the `dg.exp' driver.
|
||||
|
||||
# Load support procs.
|
||||
load_lib go-dg.exp
|
||||
|
||||
# If a testcase doesn't have special options, use these.
|
||||
global DEFAULT_GOCFLAGS
|
||||
if ![info exists DEFAULT_GOCFLAGS] then {
|
||||
set DEFAULT_GOCFLAGS " -pedantic-errors"
|
||||
}
|
||||
|
||||
# Initialize `dg'.
|
||||
dg-init
|
||||
|
||||
# Main loop.
|
||||
go-dg-runtest [lsort \
|
||||
[glob -nocomplain $srcdir/$subdir/*.go ] ] $DEFAULT_GOCFLAGS
|
||||
|
||||
# All done.
|
||||
dg-finish
|
|
@ -0,0 +1,7 @@
|
|||
// { dg-do compile }
|
||||
|
||||
package main
|
||||
|
||||
func main() {
|
||||
var ret; // { dg-error "expected type" }
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
// { dg-do compile }
|
||||
|
||||
package main
|
||||
|
||||
func main() {
|
||||
goto lab; // { dg-error "undefined label" }
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
// { dg-do compile }
|
||||
|
||||
package main
|
||||
|
||||
func main() {
|
||||
sys.Exit(i) // { dg-error "undefined" }
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package main
|
||||
var a [2]int;
|
||||
func fn() {
|
||||
a[0] = 1;
|
||||
a[1] = 1;
|
||||
}
|
||||
func main() {
|
||||
fn();
|
||||
if a[0] != a[1] { panic(0) }
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package main
|
||||
|
||||
func fn(a []int) int {
|
||||
alen := len(a);
|
||||
for i := 0; i < alen; i++ {
|
||||
a[i] = i
|
||||
}
|
||||
return alen;
|
||||
}
|
||||
|
||||
func main() {
|
||||
var a [2]int;
|
||||
if fn(a[0:]) != 2 {
|
||||
panic(0);
|
||||
}
|
||||
if a[0] != 0 || a[1] != 1 {
|
||||
panic(1);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package main
|
||||
|
||||
func main() {
|
||||
c := make(chan int, 1);
|
||||
c <- 0;
|
||||
if <-c != 0 { panic(0) }
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package main
|
||||
|
||||
func main() {
|
||||
const c = 2;
|
||||
if c != 2 { panic(0) }
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package main
|
||||
|
||||
const c = 3;
|
||||
|
||||
func main() {
|
||||
if c != 3 { panic(0) }
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
# Copyright (C) 2009 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GCC; see the file COPYING3. If not see
|
||||
# <http://www.gnu.org/licenses/>.
|
||||
|
||||
# This is based on a file written by Rob Savoye (rob@cygnus.com) and
|
||||
# Jeffrey Wheat (cassidy@cygnus.com).
|
||||
|
||||
if $tracelevel then {
|
||||
strace $tracelevel
|
||||
}
|
||||
|
||||
# load support procs
|
||||
load_lib go-torture.exp
|
||||
|
||||
foreach testcase [lsort [glob -nocomplain $srcdir/$subdir/*.go]] {
|
||||
# If we're only testing specific files and this isn't one of them, skip it.
|
||||
if ![runtest_file_p $runtests $testcase] then {
|
||||
continue
|
||||
}
|
||||
go-torture-execute $testcase
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package main
|
||||
|
||||
func main() {
|
||||
var v1 = 1;
|
||||
var v2 = 1;
|
||||
var v3 = (v1 + v2) / (v1 + v2);
|
||||
var v4 = (v3 * v3) % (v3 * v3);
|
||||
if v4 != 0 {
|
||||
panic(0)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package main
|
||||
|
||||
func main() {
|
||||
sum := 0;
|
||||
for i := 0; i < 10; i++ {
|
||||
sum += i;
|
||||
}
|
||||
if sum != 45 { panic(0) }
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package main
|
||||
|
||||
func f1() {
|
||||
j := 0;
|
||||
for i := 0; i < 10; i++ {
|
||||
if i > 2 {
|
||||
break;
|
||||
}
|
||||
j = i;
|
||||
}
|
||||
if (j != 2) {
|
||||
panic(0);
|
||||
}
|
||||
}
|
||||
|
||||
func f2() {
|
||||
for i := 0; i < 10; i++ {
|
||||
if i >= 0 {
|
||||
continue;
|
||||
}
|
||||
panic(1);
|
||||
}
|
||||
}
|
||||
|
||||
func f3() {
|
||||
lab1:
|
||||
for i := 0; i < 10; i++ {
|
||||
for j := 0; j < 10; j++ {
|
||||
if j > 2 {
|
||||
break lab1;
|
||||
}
|
||||
}
|
||||
panic(2);
|
||||
}
|
||||
}
|
||||
|
||||
func f4() {
|
||||
lab1:
|
||||
for i := 0; i < 10; i++ {
|
||||
for j := 0; j < 10; j++ {
|
||||
continue lab1;
|
||||
}
|
||||
panic(3);
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
f1();
|
||||
f2();
|
||||
f3();
|
||||
f4()
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package main
|
||||
|
||||
func subr() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func main() {
|
||||
if subr() != 0 { panic(0) }
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package main
|
||||
|
||||
func subr(p int) int {
|
||||
return p
|
||||
}
|
||||
|
||||
func main() {
|
||||
if subr(0) != 0 { panic(0) }
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package main
|
||||
|
||||
func send_one(c chan <- int) {
|
||||
c <- 0;
|
||||
}
|
||||
|
||||
func main() {
|
||||
c := make(chan int);
|
||||
go send_one(c);
|
||||
if <-c != 0 { panic(0) }
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package main
|
||||
|
||||
func send_one(c chan <- int, val int) {
|
||||
c <- val;
|
||||
}
|
||||
|
||||
func main() {
|
||||
c := make(chan int);
|
||||
go send_one(c, 0);
|
||||
if <-c != 0 { panic(0) }
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package main
|
||||
|
||||
type I interface { send(chan <- int) }
|
||||
|
||||
type S struct { v int }
|
||||
func (p *S) send(c chan <- int) { c <- p.v }
|
||||
|
||||
func main() {
|
||||
s := S{0};
|
||||
var i I = &s;
|
||||
c := make(chan int);
|
||||
go i.send(c);
|
||||
if <- c != 0 { panic(0) }
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package main
|
||||
|
||||
func main() {
|
||||
goto lab;
|
||||
panic(0);
|
||||
lab:
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package main
|
||||
|
||||
func main() {
|
||||
v := make(map[int] int);
|
||||
v[0] = 0;
|
||||
v[1000000] = 1;
|
||||
if v[0] != 0 {
|
||||
panic(1)
|
||||
}
|
||||
val, present := v[0];
|
||||
if !present || val != 0 {
|
||||
panic(2)
|
||||
}
|
||||
val = 5;
|
||||
val, present = v[1];
|
||||
if present || val != 0 {
|
||||
panic(3);
|
||||
}
|
||||
if v[2] != 0 {
|
||||
panic(4)
|
||||
}
|
||||
val, present = v[2];
|
||||
if present {
|
||||
panic(5)
|
||||
}
|
||||
if len(v) != 2 {
|
||||
panic(6)
|
||||
}
|
||||
v[0] = 0, false;
|
||||
if len(v) != 1 {
|
||||
panic(7)
|
||||
}
|
||||
|
||||
w := make(map[string] string);
|
||||
if len(w) != 0 {
|
||||
panic(8)
|
||||
}
|
||||
w["Hello"] = "world";
|
||||
w["Goodbye"] = "sweet prince";
|
||||
if w["Hello"] != "world" {
|
||||
panic(9)
|
||||
}
|
||||
if w["Hej"] != "" {
|
||||
panic(10)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package main
|
||||
type s struct { i int };
|
||||
func (v *s) val() int { return v.i }
|
||||
func main() {
|
||||
p := new(s);
|
||||
if p.val() != 0 { panic(0) }
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
package main
|
||||
func main() {
|
||||
if func (i int) int { return i} (0) != 0 { panic(0) }
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package main
|
||||
|
||||
func main() {
|
||||
p := new(int);
|
||||
*p = 0;
|
||||
if *p != 0 { panic(0) }
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
package main
|
||||
|
||||
func main() {
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package main
|
||||
|
||||
func fn() (i, j int) {
|
||||
i = 1;
|
||||
j = 2;
|
||||
return;
|
||||
}
|
||||
|
||||
func main() {
|
||||
var i, j = fn();
|
||||
var ret int;
|
||||
if i == 1 && j == 2 {
|
||||
ret = 0;
|
||||
} else {
|
||||
ret = 1;
|
||||
}
|
||||
if ret != 0 { panic(0) }
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package main
|
||||
|
||||
func fn() (i, j int) {
|
||||
return 1, 2
|
||||
}
|
||||
|
||||
func main() {
|
||||
var i, j = fn();
|
||||
var ret int;
|
||||
if i == 1 && j == 2 {
|
||||
ret = 0;
|
||||
} else {
|
||||
ret = 1;
|
||||
}
|
||||
if ret != 0 { panic(0) }
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package main
|
||||
|
||||
func main() {
|
||||
ch1 := make(chan int);
|
||||
ch2 := make(chan int);
|
||||
go func (ch1, ch2 chan int) { ch1 <- 1; ch2 <- 2; } (ch1, ch2);
|
||||
count := 0;
|
||||
var v int;
|
||||
for count != 2 {
|
||||
select
|
||||
{
|
||||
case v := <- ch1:
|
||||
if v != 1 {
|
||||
panic(0)
|
||||
}
|
||||
count++
|
||||
|
||||
case v = <- ch2:
|
||||
if v != 2 {
|
||||
panic(1)
|
||||
}
|
||||
count++
|
||||
}
|
||||
}
|
||||
if v != 2 {
|
||||
panic(2)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package main
|
||||
|
||||
func fn(s string) int {
|
||||
if s[0] != 'a' || s[1] != 'b' || s[2] != 'c' {
|
||||
panic(0);
|
||||
}
|
||||
return len(s);
|
||||
}
|
||||
|
||||
func main() {
|
||||
s := "abc";
|
||||
if fn(s) != 3 {
|
||||
panic(1);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package main
|
||||
|
||||
func fn(s string) string {
|
||||
if len(s) != 3 {
|
||||
panic(0)
|
||||
}
|
||||
i := len(s) - 1;
|
||||
return s + s[0 : i];
|
||||
}
|
||||
|
||||
func main() {
|
||||
s := fn("abc");
|
||||
if s != "abcab" {
|
||||
panic(1)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package main
|
||||
|
||||
func main() {
|
||||
type s struct { x int; };
|
||||
var ret s;
|
||||
ret.x = 1;
|
||||
if ret.x != 1 { panic(0) }
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package main
|
||||
|
||||
func main() {
|
||||
type s struct { x int; y int; };
|
||||
var ret s = s{1, 2};
|
||||
if ret.y - (ret.x + ret.x) != 0 { panic(0) }
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
package main
|
||||
|
||||
func f1(i int) bool {
|
||||
switch j := i; j {
|
||||
case 3: fallthrough
|
||||
case 1: return true
|
||||
case 2: return false
|
||||
default: return false
|
||||
case 4: return true
|
||||
}
|
||||
}
|
||||
|
||||
func f2(i int) int {
|
||||
switch {
|
||||
case i < 0: return -1
|
||||
case i > 0: return 1
|
||||
default: return 0
|
||||
case i != 0: return 1000
|
||||
}
|
||||
panic(0)
|
||||
}
|
||||
|
||||
func f3(i int) int {
|
||||
lab:
|
||||
switch i {
|
||||
case 1: break
|
||||
case 2: return 2
|
||||
case 3, 4:
|
||||
switch i {
|
||||
case 3: break lab
|
||||
case 4: break
|
||||
}
|
||||
return 4
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
func main() {
|
||||
if !f1(1) {
|
||||
panic(1);
|
||||
}
|
||||
if f1(2) {
|
||||
panic(2);
|
||||
}
|
||||
if !f1(3) {
|
||||
panic(3);
|
||||
}
|
||||
if !f1(4) {
|
||||
panic(4);
|
||||
}
|
||||
if f1(5) {
|
||||
panic(5);
|
||||
}
|
||||
|
||||
if f2(-100) != -1 {
|
||||
panic(6);
|
||||
}
|
||||
if f2(1000) != 1 {
|
||||
panic(7);
|
||||
}
|
||||
if f2(0) != 0 {
|
||||
panic(8);
|
||||
}
|
||||
|
||||
if f3(1) != 1 || f3(2) != 2 || f3(3) != 1 || f3(4) != 4 {
|
||||
panic(9);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package main
|
||||
|
||||
func main() {
|
||||
var ret = 0;
|
||||
if ret != 0 { panic(0) }
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package main
|
||||
|
||||
func main() {
|
||||
var ret int;
|
||||
if ret != 0 { panic(0) }
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package main
|
||||
|
||||
func main() {
|
||||
ret := 0;
|
||||
if ret != 0 { panic(0) }
|
||||
}
|
|
@ -0,0 +1,666 @@
|
|||
# Copyright (C) 2009, 2010 Free Software Foundation, Inc.
|
||||
# Written by Ian Lance Taylor <iant@google.com>.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GCC; see the file COPYING3. If not see
|
||||
# <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
# Test using the testsuite for the gc Go compiler. In these tests the
|
||||
# first line is a shell script to run. That line expects the
|
||||
# following environment variables to be set:
|
||||
# A The file extension of the object file and the name of the executable
|
||||
# G The name of the compiler
|
||||
# L The name of the linker
|
||||
# F The basename of the test
|
||||
# D The directory of the test.
|
||||
#
|
||||
# Typical command lines:
|
||||
# // $G $D/$F.go && $L $F.$A && ./$A.out
|
||||
# // $G $D/$F.go && $L $F.$A || echo BUG: known to fail incorrectly
|
||||
# // $G $D/$F.go && echo BUG: compilation succeeds incorrectly
|
||||
# // $G $D/$F.go || echo BUG: compilation should succeed
|
||||
|
||||
load_lib go-dg.exp
|
||||
load_lib go-torture.exp
|
||||
|
||||
# Implement errchk
|
||||
proc errchk { test } {
|
||||
global dg-do-what-default
|
||||
global DEFAULT_GOCFLAGS
|
||||
|
||||
set saved-dg-do-what-default ${dg-do-what-default}
|
||||
set dg-do-what-default compile
|
||||
set filename [file tail $test]
|
||||
if { "$filename" == "$test" } {
|
||||
set filename "errchk-$filename"
|
||||
}
|
||||
set fdin [open $test r]
|
||||
fconfigure $fdin -encoding binary
|
||||
set fdout [open $filename w]
|
||||
fconfigure $fdout -encoding binary
|
||||
while { [gets $fdin copy_line] >= 0 } {
|
||||
regsub "// \(GCCGO_\)?ERROR \"\(\[^\"\]*\)\".*$" $copy_line "// \{ dg-error \"\\2\" \}" out_line
|
||||
if [string match "*dg-error*.\**" $out_line] {
|
||||
# I worked out the right number of backslashes by
|
||||
# experimentation, not analysis.
|
||||
regsub -all "\\.\\*" $out_line "\\\\\[ -~\\\\\]*" out_line
|
||||
}
|
||||
if [string match "*dg-error*\{*" $out_line] {
|
||||
set index [string first "dg-error" $out_line]
|
||||
regsub -start $index -all "\{" $out_line "\\\\\[\\\{\\\\\]" out_line
|
||||
}
|
||||
if [string match "*dg-error*\}*\}" $out_line] {
|
||||
set index [string first "dg-error" $out_line]
|
||||
regsub -start $index -all "\}\(.\)" $out_line "\\\\\[\\\}\\\\\]\\1" out_line
|
||||
}
|
||||
if [string match "*dg-error*\[.\]*" $out_line] {
|
||||
set index [string first "dg-error" $out_line]
|
||||
regsub -all "\\\[\\.\\\]" $out_line "\\\\\[.\\\\\]" out_line
|
||||
}
|
||||
puts $fdout $out_line
|
||||
}
|
||||
close $fdin
|
||||
close $fdout
|
||||
go-dg-runtest $filename "-fno-show-column $DEFAULT_GOCFLAGS"
|
||||
file delete $filename
|
||||
set dg-do-what-default ${saved-dg-do-what-default}
|
||||
}
|
||||
|
||||
# This is an execution test which should fail.
|
||||
proc go-execute-xfail { test } {
|
||||
global DEFAULT_GOCFLAGS
|
||||
|
||||
set filename [file tail $test]
|
||||
set fdin [open $test r]
|
||||
set fdout [open $filename w]
|
||||
puts $fdout "// { dg-do run { xfail *-*-* } }"
|
||||
while { [gets $fdin copy_line] >= 0 } {
|
||||
puts $fdout $copy_line
|
||||
}
|
||||
close $fdin
|
||||
close $fdout
|
||||
go-dg-runtest $filename "-w $DEFAULT_GOCFLAGS"
|
||||
file delete $filename
|
||||
}
|
||||
|
||||
proc go-gc-tests { } {
|
||||
global srcdir subdir
|
||||
global runtests
|
||||
global GCC_UNDER_TEST
|
||||
global TOOL_OPTIONS
|
||||
global TORTURE_OPTIONS
|
||||
global dg-do-what-default
|
||||
global go_execute_args
|
||||
global target_triplet
|
||||
|
||||
# If a testcase doesn't have special options, use these.
|
||||
global DEFAULT_GOCFLAGS
|
||||
if ![info exists DEFAULT_GOCFLAGS] {
|
||||
set DEFAULT_GOCFLAGS " -pedantic-errors"
|
||||
}
|
||||
|
||||
# Running all the torture options takes too long and, since the
|
||||
# frontend ignores the standard options, it doesn't significantly
|
||||
# improve testing.
|
||||
set saved_torture_options $TORTURE_OPTIONS
|
||||
set TORTURE_OPTIONS [ list { -O2 -g }]
|
||||
|
||||
set saved-dg-do-what-default ${dg-do-what-default}
|
||||
|
||||
set testdir [pwd]
|
||||
|
||||
set tests [lsort [find $srcdir/$subdir *.go]]
|
||||
foreach test $tests {
|
||||
if ![runtest_file_p $runtests $test] {
|
||||
continue
|
||||
}
|
||||
|
||||
# Skip the files in bench and garbage; they are not tests.
|
||||
if [string match "*go.test/test/bench/*" $test] {
|
||||
continue
|
||||
}
|
||||
if [string match "*go.test/test/garbage/*" $test] {
|
||||
continue
|
||||
}
|
||||
|
||||
# Skip files in sub-subdirectories: they are components of
|
||||
# other tests.
|
||||
if [string match "*go.test/test/*/*/*" $test] {
|
||||
continue
|
||||
}
|
||||
|
||||
set name [dg-trim-dirname $srcdir $test]
|
||||
|
||||
# Skip certain tests if target is RTEMS OS.
|
||||
if [istarget "*-*-rtems*"] {
|
||||
if { [string match "*go.test/test/args.go" \
|
||||
$test] \
|
||||
|| [string match "*go.test/test/env.go" \
|
||||
$test] } {
|
||||
untested "$name: uses the command-line or environment variables"
|
||||
continue
|
||||
}
|
||||
|
||||
if { [string match "*go.test/test/stack.go" \
|
||||
$test] \
|
||||
|| [string match "*go.test/test/peano.go" \
|
||||
$test] \
|
||||
|| [string match "*go.test/test/chan/goroutines.go" \
|
||||
$test] } {
|
||||
untested "$name: has very high memory requirement"
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
set fd [open $test r]
|
||||
|
||||
set lines_ok 1
|
||||
|
||||
while 1 {
|
||||
if { [gets $fd test_line] < 0 } {
|
||||
close $fd
|
||||
clone_output "$test: could not read first line"
|
||||
unresolved $name
|
||||
set lines_ok 0
|
||||
break
|
||||
}
|
||||
|
||||
if { [ string match "*nacl*exit 0*" $test_line ] \
|
||||
|| [ string match "*exit 0*nacl*" $test_line ] \
|
||||
|| [ string match "*Android*exit 0*" $test_line ] \
|
||||
|| [ string match "*exit 0*Android*" $test_line ] } {
|
||||
continue
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
if { $lines_ok == 0 } {
|
||||
continue
|
||||
}
|
||||
|
||||
set lineno 1
|
||||
set test_line1 $test_line
|
||||
|
||||
while { [eval "string match \"//*&&\" \${test_line$lineno}"] } {
|
||||
set lineno [expr $lineno + 1]
|
||||
if { [eval "gets \$fd test_line$lineno"] < 0 } {
|
||||
close $fd
|
||||
clone_output "$test: could not read line $lineno"
|
||||
unresolved $name
|
||||
set lines_ok 0
|
||||
break
|
||||
}
|
||||
}
|
||||
if { $lines_ok == 0 } {
|
||||
continue
|
||||
}
|
||||
|
||||
close $fd
|
||||
|
||||
set go_execute_args ""
|
||||
if { [regexp ".*\\\$A.out (\[^|&>\].*)\$" $test_line match progargs] } {
|
||||
set go_execute_args $progargs
|
||||
verbose -log "$test: go_execute_args is $go_execute_args"
|
||||
set index [string last " $progargs" $test_line]
|
||||
set test_line [string replace $test_line $index end]
|
||||
}
|
||||
|
||||
if { $test_line == "// \$G \$D/\$F\.go && \$L \$F\.\$A && \./\$A\.out >tmp.go &&" \
|
||||
&& $test_line2 == "// \$G tmp\.go && \$L tmp\.\$A && \./\$A\.out || echo BUG: 64bit" } {
|
||||
# 64bit.go is a special case.
|
||||
set go_execute_args ""
|
||||
set hold_runtests $runtests
|
||||
set runtests "go-test.exp"
|
||||
set dg-do-what-default "link"
|
||||
dg-test -keep-output $test "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
set output_file "./[file rootname [file tail $test]].exe"
|
||||
set base "[file rootname [file tail $test]]"
|
||||
if [isnative] {
|
||||
if { [catch "exec $output_file >$base-out.go"] != 0 } {
|
||||
fail "$name execution"
|
||||
} else {
|
||||
pass "$name execution"
|
||||
file delete $base-out.x
|
||||
go-torture-execute "./$base-out.go"
|
||||
}
|
||||
file delete $base-out.go
|
||||
}
|
||||
file delete $output_file
|
||||
set runtests $hold_runtests
|
||||
} elseif { $test_line == "// \$G \$D/\$F.go && \$L \$F.\$A && ./\$A.out" \
|
||||
|| $test_line == "// \$G \$F.go && \$L \$F.\$A && ./\$A.out" \
|
||||
|| $test_line == "// \$G \$F.go && \$L \$F.\$A &&./\$A.out" \
|
||||
|| $test_line == "// \$G \$D/\$F.go && \$L \$F.\$A && \$A.out" \
|
||||
|| [string match \
|
||||
"// \$G \$D/\$F.go && \$L \$F.\$A && ./\$A.out || echo BUG*" \
|
||||
$test_line]
|
||||
|| [string match \
|
||||
"// \$G \$F.go && \$L \$F.\$A && (./\$A.out || echo BUG*" \
|
||||
$test_line]
|
||||
|| [string match \
|
||||
"// \$G \$D/\$F.go && \$L \$F.\$A && (./\$A.out || echo BUG*" \
|
||||
$test_line]
|
||||
|| [string match \
|
||||
"// \$G \$F.go && \$L \$F.\$A && GOMAXPROCS=* ./\$A.out" \
|
||||
$test_line]
|
||||
|| [string match \
|
||||
"// \$G \$D/\$F.go && \$L \$F.\$A && ./\$A.out >* || echo BUG*" \
|
||||
$test_line] } {
|
||||
# This is a vanilla execution test.
|
||||
go-torture-execute $test
|
||||
file delete core [glob -nocomplain core.*]
|
||||
} elseif { [string match \
|
||||
"// \$G \$D/\$F.go && \$L \$F.\$A || echo BUG*" \
|
||||
$test_line] \
|
||||
|| [string match "// \$G \$F.go && \$L \$F.\$A #*" \
|
||||
$test_line] } {
|
||||
# This is a vanilla compile and link test.
|
||||
set dg-do-what-default "link"
|
||||
go-dg-runtest $test "-w $DEFAULT_GOCFLAGS"
|
||||
} elseif { [string match "// \$G \$D/\$F.go" $test_line] \
|
||||
|| [string match "// \$G \$D/\$F.go || echo BUG*" \
|
||||
$test_line] \
|
||||
|| [string match "// \$G \$F.go || echo BUG*" \
|
||||
$test_line] \
|
||||
|| [string match "// ! \$G \$D/\$F.go && echo BUG*" \
|
||||
$test_line] } {
|
||||
# This is a vanilla compile test.
|
||||
set dg-do-what-default "assemble"
|
||||
go-dg-runtest $test "-w $DEFAULT_GOCFLAGS"
|
||||
} elseif { [string match "// \$G \$D/\$F.go && echo BUG*" \
|
||||
$test_line] \
|
||||
|| $test_line == "// ! \$G \$D/\$F.go >/dev/null" \
|
||||
|| $test_line == "// ! \$G \$D/\$F.go" \
|
||||
|| $test_line == "// ! \$G \$F.go" \
|
||||
|| [string match "// ! \$G \$D/\$F.go || echo BUG*" \
|
||||
$test_line] } {
|
||||
# This is a compile test which should fail.
|
||||
set dg-do-what-default "assemble"
|
||||
setup_xfail "*-*-*"
|
||||
go-dg-runtest $test "-w $DEFAULT_GOCFLAGS"
|
||||
} elseif { [string match "// \$G \$D/\$F.go && \$L \$F.\$A && ! ./\$A.out" \
|
||||
$test_line] \
|
||||
|| [string match "// \$G \$D/\$F.go && \$L \$F.\$A && ! ./\$A.out || echo BUG: *" \
|
||||
$test_line] \
|
||||
|| [string match "// \$G \$D/\$F.go && \$L \$F.\$A && (! ./\$A.out || echo BUG: *" \
|
||||
$test_line] \
|
||||
|| ($test_line == "// \$G \$D/\$F.go && \$L \$F.\$A &&"
|
||||
&& $test_line2 == "// ((! sh -c ./\$A.out) >/dev/null 2>&1 || echo BUG: should fail)") } {
|
||||
go-execute-xfail $test
|
||||
} elseif { [string match "// errchk \$G \$F.go" $test_line] \
|
||||
|| [string match "// errchk \$G -e \$F.go" $test_line] \
|
||||
|| [string match "// errchk \$G \$D/\$F.go" $test_line] \
|
||||
|| [string match "//errchk \$G \$D/\$F.go" $test_line] \
|
||||
|| [string match "// errchk \$G -e \$D/\$F.go" \
|
||||
$test_line] \
|
||||
|| [string match "// ! errchk \$G \$D/\$F.go" $test_line] \
|
||||
|| [string match "// ! errchk \$G -e \$D/\$F.go" \
|
||||
$test_line] \
|
||||
|| [string match "// errchk \$G \$F.go || true" \
|
||||
$test_line] \
|
||||
|| [string match "// errchk \$G \$D/\$F.go || true" \
|
||||
$test_line] \
|
||||
|| [string match "// errchk \$G -e \$D/\$F.go || true" \
|
||||
$test_line] \
|
||||
|| [string match "// errchk \$G \$D/\$F.go || echo BUG*" \
|
||||
$test_line] } {
|
||||
errchk $test
|
||||
} elseif { [string match \
|
||||
"// \$G \$D/\$F.dir/bug0.go && \$G \$D/\$F.dir/bug1.go || echo BUG*" \
|
||||
$test_line] } {
|
||||
set hold_runtests $runtests
|
||||
set runtests "go-test.exp"
|
||||
set dg-do-what-default "assemble"
|
||||
regsub "\\.go$" $test ".dir/bug0.go" file1
|
||||
dg-test -keep-output $file1 "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
regsub "\\.go$" $test ".dir/bug1.go" file2
|
||||
dg-test $file2 "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
file delete "[file rootname [file tail $file1]].o"
|
||||
set runtests $hold_runtests
|
||||
} elseif { [string match \
|
||||
"// \$G \$D/\$F.dir/bug0.go && errchk \$G \$D/\$F.dir/bug1.go" \
|
||||
$test_line] \
|
||||
|| [string match \
|
||||
"// \$G \$D/\$F.dir/p1.go && \$G \$D/\$F.dir/p2.go" \
|
||||
$test_line] } {
|
||||
if { [string match \
|
||||
"// \$G \$D/\$F.dir/p1.go && \$G \$D/\$F.dir/p2.go" \
|
||||
$test_line] } {
|
||||
set name1 "p1.go"
|
||||
set name2 "p2.go"
|
||||
} else {
|
||||
set name1 "bug0.go"
|
||||
set name2 "bug1.go"
|
||||
}
|
||||
set hold_runtests $runtests
|
||||
set runtests "go-test.exp"
|
||||
set dg-do-what-default "assemble"
|
||||
regsub "\\.go$" $test ".dir/$name1" file1
|
||||
dg-test -keep-output $file1 "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
regsub "\\.go$" $test ".dir/$name2" file2
|
||||
errchk $file2
|
||||
file delete "[file rootname [file tail $file1]].o"
|
||||
set runtests $hold_runtests
|
||||
} elseif { [string match \
|
||||
"// \$G \$D/\$F.dir/bug0.go && (! \$G \$D/\$F.dir/bug1.go || echo BUG*" \
|
||||
$test_line] } {
|
||||
set hold_runtests $runtests
|
||||
set runtests "go-test.exp"
|
||||
set dg-do-what-default "assemble"
|
||||
regsub "\\.go$" $test ".dir/bug0.go" file1
|
||||
dg-test -keep-output $file1 "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
regsub "\\.go$" $test ".dir/bug1.go" file2
|
||||
setup_xfail "*-*-*"
|
||||
dg-test $file2 "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
file delete "[file rootname [file tail $file1]].o"
|
||||
set runtests $hold_runtests
|
||||
} elseif { [string match \
|
||||
"// \$G \$D/\$F.dir/bug0.go && \$G \$D/\$F.dir/bug1.go && (! \$G \$D/\$F.dir/bug2.go || echo BUG*" \
|
||||
$test_line] } {
|
||||
set hold_runtests $runtests
|
||||
set runtests "go-test.exp"
|
||||
set dg-do-what-default "assemble"
|
||||
regsub "\\.go$" $test ".dir/bug0.go" file1
|
||||
dg-test -keep-output $file1 "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
regsub "\\.go$" $test ".dir/bug1.go" file2
|
||||
dg-test -keep-output $file2 "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
regsub "\\.go$" $test ".dir/bug2.go" file3
|
||||
setup_xfail "*-*-*"
|
||||
dg-test $file3 "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
file delete "[file rootname [file tail $file1]].o"
|
||||
file delete "[file rootname [file tail $file2]].o"
|
||||
set runtests $hold_runtests
|
||||
} elseif { [string match \
|
||||
"// \$G \$D/\$F.dir/bug0.go && \$G \$D/\$F.dir/bug1.go && errchk \$G \$D/\$F.dir/bug2.go" \
|
||||
$test_line] } {
|
||||
set hold_runtests $runtests
|
||||
set runtests "go-test.exp"
|
||||
set dg-do-what-default "assemble"
|
||||
regsub "\\.go$" $test ".dir/bug0.go" file1
|
||||
dg-test -keep-output $file1 "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
regsub "\\.go$" $test ".dir/bug1.go" file2
|
||||
dg-test -keep-output $file2 "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
regsub "\\.go$" $test ".dir/bug2.go" file3
|
||||
errchk $file3
|
||||
file delete "[file rootname [file tail $file1]].o"
|
||||
file delete "[file rootname [file tail $file2]].o"
|
||||
set runtests $hold_runtests
|
||||
} elseif { [string match \
|
||||
"// \$G \$D/bug160.dir/x.go && \$G \$D/bug160.dir/y.go && \$L y.\$A && ./\$A.out" \
|
||||
$test_line] } {
|
||||
set hold_runtests $runtests
|
||||
set runtests "go-test.exp"
|
||||
set dg-do-what-default "assemble"
|
||||
regsub "\\.go$" $test ".dir/x.go" file1
|
||||
dg-test -keep-output $file1 "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
set ofile1 "[file rootname [file tail $file1]].o"
|
||||
regsub "\\.go$" $test ".dir/y.go" file2
|
||||
dg-test -keep-output $file2 "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
set ofile2 "[file rootname [file tail $file2]].o"
|
||||
set dg-do-what-default "link"
|
||||
set output_file "./[file rootname [file tail $test]].exe"
|
||||
set comp_output [go_target_compile "$ofile1 $ofile2" \
|
||||
$output_file "executable" "$DEFAULT_GOCFLAGS"]
|
||||
set comp_output [go-dg-prune $target_triplet $comp_output]
|
||||
verbose -log $comp_output
|
||||
set result [go_load "$output_file" "" ""]
|
||||
set status [lindex $result 0]
|
||||
$status $name
|
||||
file delete $ofile1 $ofile2 $output_file
|
||||
set runtests $hold_runtests
|
||||
} elseif { [string match \
|
||||
"// \$G \$D/bug191.dir/a.go && \$G \$D/bug191.dir/b.go && \$G \$D/\$F.go && \$L \$F.\$A" \
|
||||
$test_line] } {
|
||||
set hold_runtests $runtests
|
||||
set runtests "go-test.exp"
|
||||
set dg-do-what-default "assemble"
|
||||
regsub "\\.go$" $test ".dir/a.go" file1
|
||||
dg-test -keep-output $file1 "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
set ofile1 "[file rootname [file tail $file1]].o"
|
||||
regsub "\\.go$" $test ".dir/b.go" file2
|
||||
dg-test -keep-output $file2 "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
set ofile2 "[file rootname [file tail $file2]].o"
|
||||
dg-test -keep-output "$test" "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
set ofile3 "[file rootname [file tail $test]].o"
|
||||
set dg-do-what-default "link"
|
||||
set output_file "./[file rootname [file tail $test]].exe"
|
||||
set comp_output [go_target_compile "$ofile1 $ofile2 $ofile3" \
|
||||
$output_file "executable" "$DEFAULT_GOCFLAGS"]
|
||||
set comp_output [go-dg-prune $target_triplet $comp_output]
|
||||
if [string match "" $comp_output] {
|
||||
pass $name
|
||||
} else {
|
||||
verbose -log $comp_output
|
||||
fail $name
|
||||
}
|
||||
file delete $ofile1 $ofile2 $ofile3 $output_file
|
||||
set runtests $hold_runtests
|
||||
} elseif { [string match \
|
||||
"// \$G \$D/embed0.go && \$G \$D/\$F.go && \$L \$F.\$A && ./\$A.out" \
|
||||
$test_line ] } {
|
||||
set hold_runtests $runtests
|
||||
set runtests "go-test.exp"
|
||||
set dg-do-what-default "assemble"
|
||||
regsub "/\[^/\]*$" $test "/embed0.go" file1
|
||||
dg-test -keep-output $file1 "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
set ofile1 "[file rootname [file tail $file1]].o"
|
||||
dg-test -keep-output $test "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
set ofile2 "[file rootname [file tail $test]].o"
|
||||
set output_file "./[file rootname [file tail $test]].exe"
|
||||
set comp_output [go_target_compile "$ofile1 $ofile2" \
|
||||
$output_file "executable" "$DEFAULT_GOCFLAGS"]
|
||||
set comp_output [go-dg-prune $target_triplet $comp_output]
|
||||
if [string match "" $comp_output] {
|
||||
set result [go_load "$output_file" "" ""]
|
||||
set status [lindex $result 0]
|
||||
$status $name
|
||||
} else {
|
||||
verbose -log $comp_output
|
||||
fail $name
|
||||
}
|
||||
file delete $ofile1 $ofile2 $output_file
|
||||
set runtests $hold_runtests
|
||||
} elseif { [string match \
|
||||
"// \$G \$D/\$F.dir/chanbug.go && \$G -I. \$D/\$F.dir/chanbug2.go" \
|
||||
$test_line] } {
|
||||
set hold_runtests $runtests
|
||||
set runtests "go-test.exp"
|
||||
set dg-do-what-default "assemble"
|
||||
regsub "\\.go$" $test ".dir/chanbug.go" file1
|
||||
dg-test -keep-output $file1 "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
regsub "\\.go$" $test ".dir/chanbug2.go" file2
|
||||
dg-test $file2 "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
file delete "[file rootname [file tail $file1]].o"
|
||||
set runtests $hold_runtests
|
||||
} elseif { [string match \
|
||||
"// (! \$G \$D/\$F.go) | grep 'initialization loop' *" \
|
||||
$test_line] } {
|
||||
set dg-do-what-default "assemble"
|
||||
setup_xfail "*-*-*"
|
||||
go-dg-runtest $test "-w $DEFAULT_GOCFLAGS"
|
||||
} elseif { [string match \
|
||||
"// \$G \$D/\$F.dir/x.go && errchk \$G \$D/\$F.dir/y.go" \
|
||||
$test_line] } {
|
||||
set hold_runtests $runtests
|
||||
set runtests "go-test.exp"
|
||||
set dg-do-what-default "assemble"
|
||||
regsub "\\.go$" $test ".dir/x.go" file1
|
||||
dg-test -keep-output $file1 "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
regsub "\\.go$" $test ".dir/y.go" file2
|
||||
errchk $file2
|
||||
file delete "[file rootname [file tail $file1]].o"
|
||||
set runtests $hold_runtests
|
||||
} elseif { [string match "// true*" $test_line] } {
|
||||
# Not a real test, just ignore.
|
||||
} elseif { $test_line == "// \$G \$D/\$F.dir/bug0.go &&" \
|
||||
&& $test_line2 == "// \$G \$D/\$F.dir/bug1.go &&" \
|
||||
&& $test_line3 == "// \$G \$D/\$F.dir/bug2.go &&" \
|
||||
&& $test_line4 == "// errchk \$G -e \$D/\$F.dir/bug3.go &&" \
|
||||
&& $test_line5 == "// \$L bug2.\$A &&" \
|
||||
&& [string match "// ./\$A.out || echo BUG*" $test_line6] } {
|
||||
set hold_runtests $runtests
|
||||
set runtests "go-test.exp"
|
||||
set dg-do-what-default "assemble"
|
||||
regsub "\\.go$" $test ".dir/bug0.go" file0
|
||||
dg-test -keep-output $file0 "-O -fgo-prefix=bug0" "-w $DEFAULT_GOCFLAGS"
|
||||
set ofile0 "[file rootname [file tail $file0]].o"
|
||||
regsub "\\.go$" $test ".dir/bug1.go" file1
|
||||
dg-test -keep-output $file1 "-O -fgo-prefix=bug1" "-w $DEFAULT_GOCFLAGS"
|
||||
set ofile1 "[file rootname [file tail $file1]].o"
|
||||
regsub "\\.go$" $test ".dir/bug2.go" file2
|
||||
dg-test -keep-output $file2 "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
set ofile2 "[file rootname [file tail $file2]].o"
|
||||
regsub "\\.go$" $test ".dir/bug3.go" file3
|
||||
errchk $file3
|
||||
set output_file "./[file rootname [file tail $test]].exe"
|
||||
set comp_output [go_target_compile "$ofile0 $ofile1 $ofile2" \
|
||||
$output_file "executable" "$DEFAULT_GOCFLAGS"]
|
||||
set comp-output [go-dg-prune $target_triplet $comp_output]
|
||||
if [string match "" $comp_output] {
|
||||
set result [go_load "$output_file" "" ""]
|
||||
set status [lindex $result 0]
|
||||
$status $name
|
||||
} else {
|
||||
verbose -log $comp_output
|
||||
fail $name
|
||||
}
|
||||
file delete $ofile0 $ofile1 $ofile2 $output_file
|
||||
set runtests $hold_runtests
|
||||
} elseif { $test_line == "// \$G \$D/import2.go && \$G \$D/\$F\.go" } {
|
||||
set hold_runtests $runtests
|
||||
set runtests "go-test.exp"
|
||||
set dg-do-what-default "assemble"
|
||||
regsub "/\[^/\]*$" $test "/import2.go" file1
|
||||
dg-test -keep-output $file1 "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
set ofile1 "[file rootname [file tail $file1]].o"
|
||||
dg-test $test "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
file delete $ofile1
|
||||
set runtests $hold_runtests
|
||||
} elseif { $test_line == "// \$G \$D/ddd2.go && \$G \$D/\$F.go && \$L \$F.\$A && ./\$A.out" } {
|
||||
set hold_runtests $runtests
|
||||
set runtests "go-test.exp"
|
||||
set dg-do-what-default "assemble"
|
||||
regsub "/\[^/\]*$" $test "/ddd2.go" file1
|
||||
dg-test -keep-output $file1 "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
set ofile1 "[file rootname [file tail $file1]].o"
|
||||
dg-test -keep-output $test "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
set ofile2 "[file rootname [file tail $test]].o"
|
||||
set output_file "./[file rootname [file tail $test]].exe"
|
||||
set comp_output [go_target_compile "$ofile1 $ofile2" \
|
||||
$output_file "executable" "$DEFAULT_GOCFLAGS"]
|
||||
set comp_output [go-dg-prune $target_triplet $comp_output]
|
||||
if [string match "" $comp_output] {
|
||||
set result [go_load "$output_file" "" ""]
|
||||
set status [lindex $result 0]
|
||||
$status $name
|
||||
} else {
|
||||
verbose -log $comp_output
|
||||
fail $name
|
||||
}
|
||||
file delete $ofile1 $ofile2 $output_file
|
||||
set runtests $hold_runtests
|
||||
} elseif { $test_line == "// \$G \$D/\$F.go \$D/cmplxdivide1.go && \$L \$D/\$F.\$A && ./\$A.out" } {
|
||||
regsub "/\[^/\]*$" $test "/cmplxdivide1.go" test2
|
||||
set output_file "./[file rootname [file tail $test]].o"
|
||||
set comp_output [go_target_compile "$test $test2" \
|
||||
$output_file "executable" "$DEFAULT_GOCFLAGS"]
|
||||
set comp_output [go-dg-prune $target_triplet $comp_output]
|
||||
if [string match "" $comp_output] {
|
||||
set result [go_load "$output_file" "" ""]
|
||||
set status [lindex $result 0]
|
||||
$status $name
|
||||
} else {
|
||||
verbose -log $comp_output
|
||||
fail $name
|
||||
}
|
||||
file delete $output_file
|
||||
} elseif { $test_line == "// \$G \$D/\$F.go && \$L \$F.\$A &&" \
|
||||
&& $test_line2 == "// ./\$A.out -pass 0 >tmp.go && \$G tmp.go && \$L -o tmp1.\$A tmp.\$A && ./tmp1.\$A &&" \
|
||||
&& $test_line3 == "// ./\$A.out -pass 1 >tmp.go && errchk \$G -e tmp.go &&" \
|
||||
&& $test_line4 == "// ./\$A.out -pass 2 >tmp.go && errchk \$G -e tmp.go" } {
|
||||
set go_execute_args ""
|
||||
set hold_runtests $runtests
|
||||
set runtests "go-test.exp"
|
||||
set dg-do-what-default "link"
|
||||
dg-test -keep-output $test "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
set output_file "./[file rootname [file tail $test]].exe"
|
||||
if [isnative] {
|
||||
if { [catch "exec $output_file -pass 0 >tmp.go"] != 0 } {
|
||||
fail "$name execution 0"
|
||||
} else {
|
||||
pass "$name execution 0"
|
||||
file delete tmp.x
|
||||
go-torture-execute "./tmp.go"
|
||||
}
|
||||
if { [catch "exec $output_file -pass 1 >tmp.go"] != 0 } {
|
||||
fail "$name execution 1"
|
||||
} else {
|
||||
pass "$name execution 1"
|
||||
errchk tmp.go
|
||||
}
|
||||
if { [catch "exec $output_file -pass 2 >tmp.go"] != 0 } {
|
||||
fail "$name execution 2"
|
||||
} else {
|
||||
pass "$name execution 2"
|
||||
errchk tmp.go
|
||||
}
|
||||
file delete tmp.go
|
||||
}
|
||||
file delete $output_file
|
||||
set runtests $hold_runtests
|
||||
} elseif { $test_line == "// \$G \$D/\$F.go && \$L \$F.\$A && ./\$A.out >tmp.go &&" \
|
||||
&& $test_line2 == "// errchk \$G -e tmp.go" } {
|
||||
set go_execute_args ""
|
||||
set hold_runtests $runtests
|
||||
set runtests "go-test.exp"
|
||||
set dg-do-what-default "link"
|
||||
dg-test -keep-output $test "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
set output_file "./[file rootname [file tail $test]].exe"
|
||||
if [isnative] {
|
||||
if { [catch "exec $output_file >tmp.go"] != 0 } {
|
||||
fail "$name execution"
|
||||
} else {
|
||||
pass "$name execution"
|
||||
file delete tmp.x
|
||||
errchk tmp.go
|
||||
}
|
||||
}
|
||||
file delete $output_file
|
||||
set runtests $hold_runtests
|
||||
} elseif { $test_line == "// # generated by cmplxdivide.c" } {
|
||||
# Ignore.
|
||||
} elseif { $test_line == "// \$G \$D/bug302.dir/p.go && gopack grc pp.a p.\$A && \$G \$D/bug302.dir/main.go" \
|
||||
|| $test_line == "// \$G \$D/empty.go && errchk \$G \$D/\$F.go" } {
|
||||
# These tests import the same package under two different
|
||||
# names, which gccgo does not support.
|
||||
} elseif { $test_line == "// \$G -S \$D/\$F.go | egrep initdone >/dev/null && echo FAIL || true" } {
|
||||
# This tests whether initializers are written out
|
||||
# statically. gccgo does not provide a way to test that,
|
||||
# as an initializer will be generated for any code which
|
||||
# has global variables which need to be registered as GC
|
||||
# roots.
|
||||
} else {
|
||||
clone_output "$name: unrecognized test line: $test_line"
|
||||
unsupported $name
|
||||
}
|
||||
|
||||
set go_execute_args ""
|
||||
}
|
||||
|
||||
set dg-do-what-default ${saved-dg-do-what-default}
|
||||
set TORTURE_OPTIONS $saved_torture_options
|
||||
}
|
||||
|
||||
go-gc-tests
|
|
@ -0,0 +1,72 @@
|
|||
// $G $F.go && $L $F.$A && ./$A.out
|
||||
|
||||
// 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.
|
||||
|
||||
package main
|
||||
|
||||
type T chan uint64
|
||||
|
||||
func M(f uint64) (in, out T) {
|
||||
in = make(T, 100)
|
||||
out = make(T, 100)
|
||||
go func(in, out T, f uint64) {
|
||||
for {
|
||||
out <- f*<-in
|
||||
}
|
||||
}(in, out, f)
|
||||
return in, out
|
||||
}
|
||||
|
||||
|
||||
func min(xs []uint64) uint64 {
|
||||
m := xs[0]
|
||||
for i := 1; i < len(xs); i++ {
|
||||
if xs[i] < m {
|
||||
m = xs[i]
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
|
||||
func main() {
|
||||
F := []uint64{2, 3, 5}
|
||||
var n = len(F)
|
||||
OUT := []uint64{
|
||||
2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24, 25, 27, 30, 32, 36,
|
||||
40, 45, 48, 50, 54, 60, 64, 72, 75, 80, 81, 90, 96, 100, 108, 120, 125,
|
||||
128, 135, 144, 150, 160, 162, 180, 192, 200, 216, 225, 240, 243, 250,
|
||||
256, 270, 288, 300, 320, 324, 360, 375, 384, 400, 405, 432, 450, 480,
|
||||
486, 500, 512, 540, 576, 600, 625, 640, 648, 675, 720, 729, 750, 768,
|
||||
800, 810, 864, 900, 960, 972, 1000, 1024, 1080, 1125, 1152, 1200, 1215,
|
||||
1250, 1280, 1296, 1350, 1440, 1458, 1500, 1536, 1600}
|
||||
|
||||
x := uint64(1)
|
||||
ins := make([]T, n)
|
||||
outs := make([]T, n)
|
||||
xs := make([]uint64, n)
|
||||
for i := 0; i < n; i++ {
|
||||
ins[i], outs[i] = M(F[i])
|
||||
xs[i] = x
|
||||
}
|
||||
|
||||
for i := 0; i < len(OUT); i++ {
|
||||
for i := 0; i < n; i++ {
|
||||
ins[i] <- x
|
||||
}
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
if xs[i] == x {
|
||||
xs[i] = <-outs[i]
|
||||
}
|
||||
}
|
||||
|
||||
x = min(xs)
|
||||
if x != OUT[i] {
|
||||
println("bad: ", x, " should be ", OUT[i])
|
||||
panic("235")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,709 @@
|
|||
// $G $D/$F.go && $L $F.$A && ./$A.out >tmp.go &&
|
||||
// $G tmp.go && $L tmp.$A && ./$A.out || echo BUG: 64bit
|
||||
// rm -f tmp.go
|
||||
|
||||
// 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.
|
||||
|
||||
// Generate test of 64-bit arithmetic.
|
||||
// Most synthesized routines have different cases for
|
||||
// constants vs variables and even the generated code has
|
||||
// different cases for large and small constants,
|
||||
// so try a good range of inputs.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
var bout *bufio.Writer
|
||||
|
||||
// 64-bit math without using 64-bit numbers,
|
||||
// so that we can generate the test program even
|
||||
// if the compiler has buggy or missing 64-bit support.
|
||||
|
||||
type Uint64 struct {
|
||||
hi uint32
|
||||
lo uint32
|
||||
}
|
||||
|
||||
type Int64 struct {
|
||||
hi int32
|
||||
lo uint32
|
||||
}
|
||||
|
||||
func (a Uint64) Int64() (c Int64) {
|
||||
c.hi = int32(a.hi)
|
||||
c.lo = a.lo
|
||||
return
|
||||
}
|
||||
|
||||
func (a Uint64) Cmp(b Uint64) int {
|
||||
switch {
|
||||
case a.hi < b.hi:
|
||||
return -1
|
||||
case a.hi > b.hi:
|
||||
return 1
|
||||
case a.lo < b.lo:
|
||||
return -1
|
||||
case a.lo > b.lo:
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (a Uint64) LeftShift(b uint) (c Uint64) {
|
||||
switch {
|
||||
case b >= 64:
|
||||
c.hi = 0
|
||||
c.lo = 0
|
||||
case b >= 32:
|
||||
c.hi = a.lo << (b - 32)
|
||||
c.lo = 0
|
||||
default:
|
||||
c.hi = a.hi<<b | a.lo>>(32-b)
|
||||
c.lo = a.lo << b
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (a Uint64) RightShift(b uint) (c Uint64) {
|
||||
switch {
|
||||
case b >= 64:
|
||||
c.hi = 0
|
||||
c.lo = a.hi
|
||||
case b >= 32:
|
||||
c.hi = 0
|
||||
c.lo = a.hi >> (b - 32)
|
||||
default:
|
||||
c.hi = a.hi >> b
|
||||
c.lo = a.hi<<(32-b) | a.lo>>b
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (a Uint64) LeftShift64(b Uint64) (c Uint64) {
|
||||
if b.hi != 0 || b.lo >= 64 {
|
||||
return
|
||||
}
|
||||
return a.LeftShift(uint(b.lo))
|
||||
}
|
||||
|
||||
func (a Uint64) RightShift64(b Uint64) (c Uint64) {
|
||||
if b.hi != 0 || b.lo >= 64 {
|
||||
return
|
||||
}
|
||||
return a.RightShift(uint(b.lo))
|
||||
}
|
||||
|
||||
func (a Uint64) Plus(b Uint64) (c Uint64) {
|
||||
var carry uint32
|
||||
if c.lo = a.lo + b.lo; c.lo < a.lo {
|
||||
carry = 1
|
||||
}
|
||||
c.hi = a.hi + b.hi + carry
|
||||
return
|
||||
}
|
||||
|
||||
func (a Uint64) Minus(b Uint64) (c Uint64) {
|
||||
var borrow uint32
|
||||
if c.lo = a.lo - b.lo; c.lo > a.lo {
|
||||
borrow = 1
|
||||
}
|
||||
c.hi = a.hi - b.hi - borrow
|
||||
return
|
||||
}
|
||||
|
||||
func (a Uint64) Neg() (c Uint64) {
|
||||
var zero Uint64
|
||||
return zero.Minus(a)
|
||||
}
|
||||
|
||||
func (a Uint64) Com() (c Uint64) {
|
||||
c.hi = ^a.hi
|
||||
c.lo = ^a.lo
|
||||
return
|
||||
}
|
||||
|
||||
func (a Uint64) Len() int {
|
||||
switch {
|
||||
case a.hi != 0:
|
||||
for i := 31; i >= 0; i-- {
|
||||
if a.hi&(1<<uint(i)) != 0 {
|
||||
return i + 1 + 32
|
||||
}
|
||||
}
|
||||
case a.lo != 0:
|
||||
for i := 31; i >= 0; i-- {
|
||||
if a.lo&(1<<uint(i)) != 0 {
|
||||
return i + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (a Uint64) HasBit(b uint) bool {
|
||||
switch {
|
||||
case b >= 64:
|
||||
return false
|
||||
case b >= 32:
|
||||
return a.hi&(1<<(b-32)) != 0
|
||||
}
|
||||
return a.lo&(1<<b) != 0
|
||||
}
|
||||
|
||||
func (a Uint64) Times(b Uint64) (c Uint64) {
|
||||
for i := uint(0); i < 64; i++ {
|
||||
if b.HasBit(i) {
|
||||
c = c.Plus(a.LeftShift(i))
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (a Uint64) DivMod(b Uint64) (quo, rem Uint64) {
|
||||
n := a.Len() - b.Len()
|
||||
if n >= 0 {
|
||||
b = b.LeftShift(uint(n))
|
||||
for i := 0; i <= n; i++ {
|
||||
quo = quo.LeftShift(1)
|
||||
if b.Cmp(a) <= 0 { // b <= a
|
||||
quo.lo |= 1
|
||||
a = a.Minus(b)
|
||||
}
|
||||
b = b.RightShift(1)
|
||||
}
|
||||
}
|
||||
rem = a
|
||||
return
|
||||
}
|
||||
|
||||
func (a Uint64) And(b Uint64) (c Uint64) {
|
||||
c.hi = a.hi & b.hi
|
||||
c.lo = a.lo & b.lo
|
||||
return
|
||||
}
|
||||
|
||||
func (a Uint64) AndNot(b Uint64) (c Uint64) {
|
||||
c.hi = a.hi &^ b.hi
|
||||
c.lo = a.lo &^ b.lo
|
||||
return
|
||||
}
|
||||
|
||||
func (a Uint64) Or(b Uint64) (c Uint64) {
|
||||
c.hi = a.hi | b.hi
|
||||
c.lo = a.lo | b.lo
|
||||
return
|
||||
}
|
||||
|
||||
func (a Uint64) Xor(b Uint64) (c Uint64) {
|
||||
c.hi = a.hi ^ b.hi
|
||||
c.lo = a.lo ^ b.lo
|
||||
return
|
||||
}
|
||||
|
||||
func (a Uint64) String() string { return fmt.Sprintf("%#x%08x", a.hi, a.lo) }
|
||||
|
||||
func (a Int64) Uint64() (c Uint64) {
|
||||
c.hi = uint32(a.hi)
|
||||
c.lo = a.lo
|
||||
return
|
||||
}
|
||||
|
||||
func (a Int64) Cmp(b Int64) int {
|
||||
// Same body as Uint64.Cmp,
|
||||
// but behaves differently
|
||||
// because hi is uint32 not int32.
|
||||
switch {
|
||||
case a.hi < b.hi:
|
||||
return -1
|
||||
case a.hi > b.hi:
|
||||
return 1
|
||||
case a.lo < b.lo:
|
||||
return -1
|
||||
case a.lo > b.lo:
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (a Int64) LeftShift(b uint) (c Int64) { return a.Uint64().LeftShift(b).Int64() }
|
||||
|
||||
func (a Int64) RightShift(b uint) (c Int64) {
|
||||
switch {
|
||||
case b >= 64:
|
||||
c.hi = a.hi >> 31 // sign extend
|
||||
c.lo = uint32(c.hi)
|
||||
case b >= 32:
|
||||
c.hi = a.hi >> 31 // sign extend
|
||||
c.lo = uint32(a.hi >> (b - 32))
|
||||
default:
|
||||
c.hi = a.hi >> b
|
||||
c.lo = uint32(a.hi<<(32-b)) | a.lo>>b
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (a Int64) LeftShift64(b Uint64) (c Int64) {
|
||||
if b.hi != 0 || b.lo >= 64 {
|
||||
return
|
||||
}
|
||||
return a.LeftShift(uint(b.lo))
|
||||
}
|
||||
|
||||
func (a Int64) RightShift64(b Uint64) (c Int64) {
|
||||
if b.hi != 0 || b.lo >= 64 {
|
||||
return a.RightShift(64)
|
||||
}
|
||||
return a.RightShift(uint(b.lo))
|
||||
}
|
||||
|
||||
func (a Int64) Plus(b Int64) (c Int64) { return a.Uint64().Plus(b.Uint64()).Int64() }
|
||||
|
||||
func (a Int64) Minus(b Int64) (c Int64) { return a.Uint64().Minus(b.Uint64()).Int64() }
|
||||
|
||||
func (a Int64) Neg() (c Int64) { return a.Uint64().Neg().Int64() }
|
||||
|
||||
func (a Int64) Com() (c Int64) { return a.Uint64().Com().Int64() }
|
||||
|
||||
func (a Int64) Times(b Int64) (c Int64) { return a.Uint64().Times(b.Uint64()).Int64() }
|
||||
|
||||
func (a Int64) DivMod(b Int64) (quo Int64, rem Int64) {
|
||||
var zero Int64
|
||||
|
||||
quoSign := +1
|
||||
remSign := +1
|
||||
if a.Cmp(zero) < 0 {
|
||||
quoSign = -1
|
||||
remSign = -1
|
||||
a = a.Neg()
|
||||
}
|
||||
if b.Cmp(zero) < 0 {
|
||||
quoSign = -quoSign
|
||||
b = b.Neg()
|
||||
}
|
||||
|
||||
q, r := a.Uint64().DivMod(b.Uint64())
|
||||
quo = q.Int64()
|
||||
rem = r.Int64()
|
||||
|
||||
if quoSign < 0 {
|
||||
quo = quo.Neg()
|
||||
}
|
||||
if remSign < 0 {
|
||||
rem = rem.Neg()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (a Int64) And(b Int64) (c Int64) { return a.Uint64().And(b.Uint64()).Int64() }
|
||||
|
||||
func (a Int64) AndNot(b Int64) (c Int64) { return a.Uint64().AndNot(b.Uint64()).Int64() }
|
||||
|
||||
func (a Int64) Or(b Int64) (c Int64) { return a.Uint64().Or(b.Uint64()).Int64() }
|
||||
|
||||
func (a Int64) Xor(b Int64) (c Int64) { return a.Uint64().Xor(b.Uint64()).Int64() }
|
||||
|
||||
func (a Int64) String() string {
|
||||
if a.hi < 0 {
|
||||
return fmt.Sprintf("-%s", a.Neg().Uint64())
|
||||
}
|
||||
return a.Uint64().String()
|
||||
}
|
||||
|
||||
var int64Values = []Int64{
|
||||
Int64{0, 0},
|
||||
Int64{0, 1},
|
||||
Int64{0, 2},
|
||||
Int64{0, 3},
|
||||
Int64{0, 100},
|
||||
Int64{0, 10001},
|
||||
Int64{0, 1<<31 - 1},
|
||||
Int64{0, 1 << 31},
|
||||
Int64{0, 1<<31 + 1},
|
||||
Int64{0, 1<<32 - 1<<30},
|
||||
Int64{0, 1<<32 - 1},
|
||||
Int64{1, 0},
|
||||
Int64{1, 1},
|
||||
Int64{2, 0},
|
||||
Int64{1<<31 - 1, 1<<32 - 10000},
|
||||
Int64{1<<31 - 1, 1<<32 - 1},
|
||||
Int64{0x789abcde, 0xf0123456},
|
||||
|
||||
Int64{-1, 1<<32 - 1},
|
||||
Int64{-1, 1<<32 - 2},
|
||||
Int64{-1, 1<<32 - 3},
|
||||
Int64{-1, 1<<32 - 100},
|
||||
Int64{-1, 1<<32 - 10001},
|
||||
Int64{-1, 1<<32 - (1<<31 - 1)},
|
||||
Int64{-1, 1<<32 - 1<<31},
|
||||
Int64{-1, 1<<32 - (1<<31 + 1)},
|
||||
Int64{-1, 1<<32 - (1<<32 - 1<<30)},
|
||||
Int64{-1, 0},
|
||||
Int64{-1, 1},
|
||||
Int64{-2, 0},
|
||||
Int64{-(1 << 31), 10000},
|
||||
Int64{-(1 << 31), 1},
|
||||
Int64{-(1 << 31), 0},
|
||||
Int64{-0x789abcde, 0xf0123456},
|
||||
}
|
||||
|
||||
var uint64Values = []Uint64{
|
||||
Uint64{0, 0},
|
||||
Uint64{0, 1},
|
||||
Uint64{0, 2},
|
||||
Uint64{0, 3},
|
||||
Uint64{0, 100},
|
||||
Uint64{0, 10001},
|
||||
Uint64{0, 1<<31 - 1},
|
||||
Uint64{0, 1 << 31},
|
||||
Uint64{0, 1<<31 + 1},
|
||||
Uint64{0, 1<<32 - 1<<30},
|
||||
Uint64{0, 1<<32 - 1},
|
||||
Uint64{1, 0},
|
||||
Uint64{1, 1},
|
||||
Uint64{2, 0},
|
||||
Uint64{1<<31 - 1, 1<<32 - 10000},
|
||||
Uint64{1<<31 - 1, 1<<32 - 1},
|
||||
Uint64{1<<32 - 1<<30, 0},
|
||||
Uint64{1<<32 - 1, 0},
|
||||
Uint64{1<<32 - 1, 1<<32 - 100},
|
||||
Uint64{1<<32 - 1, 1<<32 - 1},
|
||||
Uint64{0x789abcde, 0xf0123456},
|
||||
Uint64{0xfedcba98, 0x76543210},
|
||||
}
|
||||
|
||||
var shiftValues = []Uint64{
|
||||
Uint64{0, 0},
|
||||
Uint64{0, 1},
|
||||
Uint64{0, 2},
|
||||
Uint64{0, 3},
|
||||
Uint64{0, 15},
|
||||
Uint64{0, 16},
|
||||
Uint64{0, 17},
|
||||
Uint64{0, 31},
|
||||
Uint64{0, 32},
|
||||
Uint64{0, 33},
|
||||
Uint64{0, 61},
|
||||
Uint64{0, 62},
|
||||
Uint64{0, 63},
|
||||
Uint64{0, 64},
|
||||
Uint64{0, 65},
|
||||
Uint64{0, 1<<32 - 1},
|
||||
Uint64{1, 0},
|
||||
Uint64{1, 1},
|
||||
Uint64{1 << 28, 0},
|
||||
Uint64{1 << 31, 0},
|
||||
Uint64{1<<32 - 1, 0},
|
||||
Uint64{1<<32 - 1, 1<<32 - 1},
|
||||
}
|
||||
|
||||
var ntest = 0
|
||||
|
||||
// Part 1 is tests of variable operations; generic functions
|
||||
// called by repetitive code. Could make a table but not worth it.
|
||||
|
||||
const prolog = "\n" +
|
||||
"package main\n" +
|
||||
"\n" +
|
||||
"import \"os\"\n" +
|
||||
"\n" +
|
||||
"var ok = true\n" +
|
||||
"\n" +
|
||||
"func testInt64Unary(a, plus, xor, minus int64) {\n" +
|
||||
" if n, op, want := +a, `+`, plus; n != want { ok=false; println(`int64`, op, a, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := ^a, `^`, xor; n != want { ok=false; println(`int64`, op, a, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := -a, `-`, minus; n != want { ok=false; println(`int64`, op, a, `=`, n, `should be`, want); }\n" +
|
||||
"}\n" +
|
||||
"\n" +
|
||||
"func testInt64Binary(a, b, add, sub, mul, div, mod, and, or, xor, andnot int64, dodiv bool) {\n" +
|
||||
" if n, op, want := a + b, `+`, add; n != want { ok=false; println(`int64`, a, op, b, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := a - b, `-`, sub; n != want { ok=false; println(`int64`, a, op, b, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := a * b, `*`, mul; n != want { ok=false; println(`int64`, a, op, b, `=`, n, `should be`, want); }\n" +
|
||||
" if dodiv {\n" +
|
||||
" if n, op, want := a / b, `/`, div; n != want { ok=false; println(`int64`, a, op, b, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := a % b, `%`, mod; n != want { ok=false; println(`int64`, a, op, b, `=`, n, `should be`, want); }\n" +
|
||||
" }\n" +
|
||||
" if n, op, want := a & b, `&`, and; n != want { ok=false; println(`int64`, a, op, b, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := a | b, `|`, or; n != want { ok=false; println(`int64`, a, op, b, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := a ^ b, `^`, xor; n != want { ok=false; println(`int64`, a, op, b, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := a &^ b, `&^`, andnot; n != want { ok=false; println(`int64`, a, op, b, `=`, n, `should be`, want); }\n" +
|
||||
"}\n" +
|
||||
"\n" +
|
||||
"func testInt64Shift(a int64, b uint64, left, right int64) {\n" +
|
||||
" if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`int64`, a, op, `uint64`, s, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`int64`, a, op, `uint64`, s, `=`, n, `should be`, want); }\n" +
|
||||
" if uint64(uint(b)) == b {\n" +
|
||||
" b := uint(b);\n" +
|
||||
" if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`int64`, a, op, `uint`, s, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`int64`, a, op, `uint`, s, `=`, n, `should be`, want); }\n" +
|
||||
" }\n" +
|
||||
" if uint64(uint32(b)) == b {\n" +
|
||||
" b := uint32(b);\n" +
|
||||
" if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`int64`, a, op, `uint32`, s, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`int64`, a, op, `uint32`, s, `=`, n, `should be`, want); }\n" +
|
||||
" }\n" +
|
||||
" if uint64(uint16(b)) == b {\n" +
|
||||
" b := uint16(b);\n" +
|
||||
" if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`int64`, a, op, `uint16`, s, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`int64`, a, op, `uint16`, s, `=`, n, `should be`, want); }\n" +
|
||||
" }\n" +
|
||||
" if uint64(uint8(b)) == b {\n" +
|
||||
" b := uint8(b);\n" +
|
||||
" if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`int64`, a, op, `uint8`, s, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`int64`, a, op, `uint8`, s, `=`, n, `should be`, want); }\n" +
|
||||
" }\n" +
|
||||
"}\n" +
|
||||
"\n" +
|
||||
"func testUint64Unary(a, plus, xor, minus uint64) {\n" +
|
||||
" if n, op, want := +a, `+`, plus; n != want { ok=false; println(`uint64`, op, a, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := ^a, `^`, xor; n != want { ok=false; println(`uint64`, op, a, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := -a, `-`, minus; n != want { ok=false; println(`uint64`, op, a, `=`, n, `should be`, want); }\n" +
|
||||
"}\n" +
|
||||
"\n" +
|
||||
"func testUint64Binary(a, b, add, sub, mul, div, mod, and, or, xor, andnot uint64, dodiv bool) {\n" +
|
||||
" if n, op, want := a + b, `+`, add; n != want { ok=false; println(`uint64`, a, op, b, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := a - b, `-`, sub; n != want { ok=false; println(`uint64`, a, op, b, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := a * b, `*`, mul; n != want { ok=false; println(`uint64`, a, op, b, `=`, n, `should be`, want); }\n" +
|
||||
" if dodiv {\n" +
|
||||
" if n, op, want := a / b, `/`, div; n != want { ok=false; println(`uint64`, a, op, b, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := a % b, `%`, mod; n != want { ok=false; println(`uint64`, a, op, b, `=`, n, `should be`, want); }\n" +
|
||||
" }\n" +
|
||||
" if n, op, want := a & b, `&`, and; n != want { ok=false; println(`uint64`, a, op, b, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := a | b, `|`, or; n != want { ok=false; println(`uint64`, a, op, b, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := a ^ b, `^`, xor; n != want { ok=false; println(`uint64`, a, op, b, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := a &^ b, `&^`, andnot; n != want { ok=false; println(`uint64`, a, op, b, `=`, n, `should be`, want); }\n" +
|
||||
"}\n" +
|
||||
"\n" +
|
||||
"func testUint64Shift(a, b, left, right uint64) {\n" +
|
||||
" if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`uint64`, a, op, `uint64`, s, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`uint64`, a, op, `uint64`, s, `=`, n, `should be`, want); }\n" +
|
||||
" if uint64(uint(b)) == b {\n" +
|
||||
" b := uint(b);\n" +
|
||||
" if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`uint64`, a, op, `uint`, s, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`uint64`, a, op, `uint`, s, `=`, n, `should be`, want); }\n" +
|
||||
" }\n" +
|
||||
" if uint64(uint32(b)) == b {\n" +
|
||||
" b := uint32(b);\n" +
|
||||
" if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`uint64`, a, op, `uint32`, s, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`uint64`, a, op, `uint32`, s, `=`, n, `should be`, want); }\n" +
|
||||
" }\n" +
|
||||
" if uint64(uint16(b)) == b {\n" +
|
||||
" b := uint16(b);\n" +
|
||||
" if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`uint64`, a, op, `uint16`, s, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`uint64`, a, op, `uint16`, s, `=`, n, `should be`, want); }\n" +
|
||||
" }\n" +
|
||||
" if uint64(uint8(b)) == b {\n" +
|
||||
" b := uint8(b);\n" +
|
||||
" if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`uint64`, a, op, `uint8`, s, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`uint64`, a, op, `uint8`, s, `=`, n, `should be`, want); }\n" +
|
||||
" }\n" +
|
||||
"}\n" +
|
||||
"\n"
|
||||
|
||||
func varTests() {
|
||||
fmt.Fprint(bout, prolog)
|
||||
for _, a := range int64Values {
|
||||
fmt.Fprintf(bout, "func test%v() {\n", ntest)
|
||||
ntest++
|
||||
fmt.Fprintf(bout, "\ttestInt64Unary(%v, %v, %v, %v);\n", a, a, a.Com(), a.Neg())
|
||||
for _, b := range int64Values {
|
||||
var div, mod Int64
|
||||
dodiv := false
|
||||
var zero Int64
|
||||
if b.Cmp(zero) != 0 { // b != 0
|
||||
// Can't divide by zero but also can't divide -0x8000...000 by -1.
|
||||
var bigneg = Int64{-0x80000000, 0}
|
||||
var minus1 = Int64{-1, ^uint32(0)}
|
||||
if a.Cmp(bigneg) != 0 || b.Cmp(minus1) != 0 { // a != -1<<63 || b != -1
|
||||
div, mod = a.DivMod(b)
|
||||
dodiv = true
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(bout, "\ttestInt64Binary(%v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v);\n",
|
||||
a, b, a.Plus(b), a.Minus(b), a.Times(b), div, mod,
|
||||
a.And(b), a.Or(b), a.Xor(b), a.AndNot(b), dodiv)
|
||||
}
|
||||
for _, b := range shiftValues {
|
||||
fmt.Fprintf(bout, "\ttestInt64Shift(%v, %v, %v, %v);\n",
|
||||
a, b, a.LeftShift64(b), a.RightShift64(b))
|
||||
}
|
||||
fmt.Fprintf(bout, "}\n")
|
||||
}
|
||||
|
||||
for _, a := range uint64Values {
|
||||
fmt.Fprintf(bout, "func test%v() {\n", ntest)
|
||||
ntest++
|
||||
fmt.Fprintf(bout, "\ttestUint64Unary(%v, %v, %v, %v);\n", a, a, a.Com(), a.Neg())
|
||||
for _, b := range uint64Values {
|
||||
var div, mod Uint64
|
||||
dodiv := false
|
||||
var zero Uint64
|
||||
if b.Cmp(zero) != 0 { // b != 0
|
||||
div, mod = a.DivMod(b)
|
||||
dodiv = true
|
||||
}
|
||||
fmt.Fprintf(bout, "\ttestUint64Binary(%v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v);\n",
|
||||
a, b, a.Plus(b), a.Minus(b), a.Times(b), div, mod,
|
||||
a.And(b), a.Or(b), a.Xor(b), a.AndNot(b), dodiv)
|
||||
}
|
||||
for _, b := range shiftValues {
|
||||
fmt.Fprintf(bout, "\ttestUint64Shift(%v, %v, %v, %v);\n",
|
||||
a, b, a.LeftShift64(b), a.RightShift64(b))
|
||||
}
|
||||
fmt.Fprintf(bout, "}\n")
|
||||
}
|
||||
}
|
||||
|
||||
// Part 2 is tests of operations involving one variable and one constant.
|
||||
|
||||
const binaryConstL = "func test%vBinaryL%v(b, add, sub, mul, div, mod, and, or, xor, andnot %v, dodiv bool) {\n" +
|
||||
" const a %v = %v;\n" +
|
||||
" const typ = `%s`;\n" +
|
||||
" if n, op, want := a + b, `+`, add; n != want { ok=false; println(typ, `const`, a, op, `var`, b, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := a - b, `-`, sub; n != want { ok=false; println(typ, `const`, a, op, `var`, b, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := a * b, `*`, mul; n != want { ok=false; println(typ, `const`, a, op, `var`, b, `=`, n, `should be`, want); }\n" +
|
||||
" if dodiv {\n" +
|
||||
" if n, op, want := a / b, `/`, div; n != want { ok=false; println(typ, `const`, a, op, `var`, b, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := a %% b, `%%`, mod; n != want { ok=false; println(typ, `const`, a, op, `var`, b, `=`, n, `should be`, want); }\n" +
|
||||
" }\n" +
|
||||
" if n, op, want := a & b, `&`, and; n != want { ok=false; println(typ, `const`, a, op, `var`, b, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := a | b, `|`, or; n != want { ok=false; println(typ, `const`, a, op, `var`, b, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := a ^ b, `^`, xor; n != want { ok=false; println(typ, `const`, a, op, `var`, b, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := a &^ b, `&^`, andnot; n != want { ok=false; println(typ, `const`, a, op, `var`, b, `=`, n, `should be`, want); }\n" +
|
||||
"}\n" +
|
||||
"\n"
|
||||
|
||||
const binaryConstR = "func test%vBinaryR%v(a, add, sub, mul, div, mod, and, or, xor, andnot %v, dodiv bool) {\n" +
|
||||
" const b %v = %v;\n" +
|
||||
" const typ = `%s`;\n" +
|
||||
" if n, op, want := a + b, `+`, add; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := a - b, `-`, sub; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := a * b, `*`, mul; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
|
||||
" if dodiv {\n" +
|
||||
" if n, op, want := a / b, `/`, div; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := a %% b, `%%`, mod; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
|
||||
" }\n" +
|
||||
" if n, op, want := a & b, `&`, and; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := a | b, `|`, or; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := a ^ b, `^`, xor; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := a &^ b, `&^`, andnot; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
|
||||
"}\n" +
|
||||
"\n"
|
||||
|
||||
const shiftConstL = "func test%vShiftL%v(b uint64, left, right %v) {\n" +
|
||||
" const a %v = %v;\n" +
|
||||
" const typ = `%s`;\n" +
|
||||
" if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(typ, `const`, a, op, `var`, s, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(typ, `const`, a, op, `var`, s, `=`, n, `should be`, want); }\n" +
|
||||
" if uint64(uint32(b)) == b {\n" +
|
||||
" b := uint32(b);\n" +
|
||||
" if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(typ, `const`, a, op, `var`, s, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(typ, `const`, a, op, `var`, s, `=`, n, `should be`, want); }\n" +
|
||||
" }\n" +
|
||||
"}\n"
|
||||
|
||||
const shiftConstR = "func test%vShiftR%v(a, left, right %v) {\n" +
|
||||
" const b uint64 = %v;\n" +
|
||||
" const typ = `%s`;\n" +
|
||||
" if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(typ, `var`, a, op, `const`, s, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(typ, `var`, a, op, `const`, s, `=`, n, `should be`, want); }\n" +
|
||||
" if b & 0xffffffff == b {\n" +
|
||||
" const b = uint32(b & 0xffffffff);\n" +
|
||||
" if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(typ, `var`, a, op, `const`, s, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(typ, `var`, a, op, `const`, s, `=`, n, `should be`, want); }\n" +
|
||||
" }\n" +
|
||||
"}\n"
|
||||
|
||||
func constTests() {
|
||||
for i, a := range int64Values {
|
||||
fmt.Fprintf(bout, binaryConstL, "Int64", i, "int64", "int64", a, "int64")
|
||||
fmt.Fprintf(bout, binaryConstR, "Int64", i, "int64", "int64", a, "int64")
|
||||
fmt.Fprintf(bout, shiftConstL, "Int64", i, "int64", "int64", a, "int64")
|
||||
}
|
||||
for i, a := range uint64Values {
|
||||
fmt.Fprintf(bout, binaryConstL, "Uint64", i, "uint64", "uint64", a, "uint64")
|
||||
fmt.Fprintf(bout, binaryConstR, "Uint64", i, "uint64", "uint64", a, "uint64")
|
||||
fmt.Fprintf(bout, shiftConstL, "Uint64", i, "uint64", "uint64", a, "uint64")
|
||||
}
|
||||
for i, a := range shiftValues {
|
||||
fmt.Fprintf(bout, shiftConstR, "Int64", i, "int64", a, "int64")
|
||||
fmt.Fprintf(bout, shiftConstR, "Uint64", i, "uint64", a, "uint64")
|
||||
}
|
||||
for i, a := range int64Values {
|
||||
fmt.Fprintf(bout, "func test%v() {\n", ntest)
|
||||
ntest++
|
||||
for j, b := range int64Values {
|
||||
var div, mod Int64
|
||||
dodiv := false
|
||||
var zero Int64
|
||||
if b.Cmp(zero) != 0 { // b != 0
|
||||
// Can't divide by zero but also can't divide -0x8000...000 by -1.
|
||||
var bigneg = Int64{-0x80000000, 0}
|
||||
var minus1 = Int64{-1, ^uint32(0)}
|
||||
if a.Cmp(bigneg) != 0 || b.Cmp(minus1) != 0 { // a != -1<<63 || b != -1
|
||||
div, mod = a.DivMod(b)
|
||||
dodiv = true
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(bout, "\ttestInt64BinaryL%v(%v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v);\n",
|
||||
i, b, a.Plus(b), a.Minus(b), a.Times(b), div, mod,
|
||||
a.And(b), a.Or(b), a.Xor(b), a.AndNot(b), dodiv)
|
||||
fmt.Fprintf(bout, "\ttestInt64BinaryR%v(%v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v);\n",
|
||||
j, a, a.Plus(b), a.Minus(b), a.Times(b), div, mod,
|
||||
a.And(b), a.Or(b), a.Xor(b), a.AndNot(b), dodiv)
|
||||
}
|
||||
for j, b := range shiftValues {
|
||||
fmt.Fprintf(bout, "\ttestInt64ShiftL%v(%v, %v, %v);\n",
|
||||
i, b, a.LeftShift64(b), a.RightShift64(b))
|
||||
fmt.Fprintf(bout, "\ttestInt64ShiftR%v(%v, %v, %v);\n",
|
||||
j, a, a.LeftShift64(b), a.RightShift64(b))
|
||||
}
|
||||
fmt.Fprintf(bout, "}\n")
|
||||
}
|
||||
for i, a := range uint64Values {
|
||||
fmt.Fprintf(bout, "func test%v() {\n", ntest)
|
||||
ntest++
|
||||
for j, b := range uint64Values {
|
||||
var div, mod Uint64
|
||||
dodiv := false
|
||||
var zero Uint64
|
||||
if b.Cmp(zero) != 0 { // b != 0
|
||||
div, mod = a.DivMod(b)
|
||||
dodiv = true
|
||||
}
|
||||
fmt.Fprintf(bout, "\ttestUint64BinaryL%v(%v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v);\n",
|
||||
i, b, a.Plus(b), a.Minus(b), a.Times(b), div, mod,
|
||||
a.And(b), a.Or(b), a.Xor(b), a.AndNot(b), dodiv)
|
||||
fmt.Fprintf(bout, "\ttestUint64BinaryR%v(%v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v);\n",
|
||||
j, a, a.Plus(b), a.Minus(b), a.Times(b), div, mod,
|
||||
a.And(b), a.Or(b), a.Xor(b), a.AndNot(b), dodiv)
|
||||
}
|
||||
for j, b := range shiftValues {
|
||||
fmt.Fprintf(bout, "\ttestUint64ShiftL%v(%v, %v, %v);\n",
|
||||
i, b, a.LeftShift64(b), a.RightShift64(b))
|
||||
fmt.Fprintf(bout, "\ttestUint64ShiftR%v(%v, %v, %v);\n",
|
||||
j, a, a.LeftShift64(b), a.RightShift64(b))
|
||||
}
|
||||
fmt.Fprintf(bout, "}\n")
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
bout = bufio.NewWriter(os.Stdout)
|
||||
varTests()
|
||||
constTests()
|
||||
|
||||
fmt.Fprintf(bout, "func main() {\n")
|
||||
for i := 0; i < ntest; i++ {
|
||||
fmt.Fprintf(bout, "\ttest%v();\n", i)
|
||||
}
|
||||
fmt.Fprintf(bout, "\tif !ok { os.Exit(1) }\n")
|
||||
fmt.Fprintf(bout, "}\n")
|
||||
bout.Flush()
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
This directory is an exact copy (except for this file) of the Go
|
||||
testsuite from the test subdirectory of http://code.google.com/p/go.
|
||||
This is here so that we run the same tests as the gc Go compiler. We
|
||||
do not, however, run the tests in the same way. The gc compiler uses
|
||||
the run shell script in this directory. For gccgo, we use the file
|
||||
go-test.exp in the parent directory to run the tests in gcc's usual
|
||||
DejaGNU test harness.
|
|
@ -0,0 +1,21 @@
|
|||
// $G $F.go && $L $F.$A && ./$A.out arg1 arg2
|
||||
|
||||
// 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.
|
||||
|
||||
package main
|
||||
|
||||
import "os"
|
||||
|
||||
func main() {
|
||||
if len(os.Args) != 3 {
|
||||
panic("argc")
|
||||
}
|
||||
if os.Args[1] != "arg1" {
|
||||
panic("arg1")
|
||||
}
|
||||
if os.Args[2] != "arg2" {
|
||||
panic("arg2")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,488 @@
|
|||
./235.go
|
||||
# ./64bit.go # fail, flaky on android build
|
||||
./args.go
|
||||
./assign.go
|
||||
./assign1.go
|
||||
./bigalg.go
|
||||
./bigmap.go
|
||||
./blank.go
|
||||
./blank1.go
|
||||
./chancap.go
|
||||
./char_lit.go
|
||||
./char_lit1.go
|
||||
./closedchan.go
|
||||
./closure.go
|
||||
./cmp1.go
|
||||
./cmp2.go
|
||||
./cmp3.go
|
||||
./cmp4.go
|
||||
./cmp5.go
|
||||
./cmplx.go
|
||||
# ./cmplxdivide.go # fail, BUG
|
||||
./cmplxdivide1.go
|
||||
./complit.go
|
||||
./compos.go
|
||||
./const.go
|
||||
./const1.go
|
||||
./const2.go
|
||||
./const3.go
|
||||
./convert.go
|
||||
./convert3.go
|
||||
./convlit.go
|
||||
./convlit1.go
|
||||
./copy.go
|
||||
./ddd.go
|
||||
./ddd1.go
|
||||
./ddd2.go
|
||||
./ddd3.go
|
||||
./decl.go
|
||||
./declbad.go
|
||||
./defer.go
|
||||
./deferprint.go
|
||||
./empty.go
|
||||
./env.go
|
||||
./escape.go
|
||||
./float_lit.go
|
||||
./floatcmp.go
|
||||
./for.go
|
||||
./func.go
|
||||
./func1.go
|
||||
./func2.go
|
||||
./func3.go
|
||||
./func4.go
|
||||
./func5.go
|
||||
./gc.go
|
||||
./gc1.go
|
||||
./hashmap.go
|
||||
./helloworld.go
|
||||
./if.go
|
||||
./if1.go
|
||||
./import.go
|
||||
./import1.go
|
||||
./import2.go
|
||||
./import3.go
|
||||
./import4.go
|
||||
./indirect.go
|
||||
./indirect1.go
|
||||
./initcomma.go
|
||||
./initialize.go
|
||||
./initializerr.go
|
||||
./initsyscall.go
|
||||
./int_lit.go
|
||||
./intcvt.go
|
||||
./iota.go
|
||||
./literal.go
|
||||
./malloc1.go
|
||||
# ./mallocfin.go # fail
|
||||
./mallocrand.go
|
||||
./mallocrep.go
|
||||
./mallocrep1.go
|
||||
# ./map.go # fail
|
||||
./method.go
|
||||
./method1.go
|
||||
./method2.go
|
||||
./method3.go
|
||||
./named.go
|
||||
./named1.go
|
||||
./nil.go
|
||||
./nul1.go
|
||||
./parentype.go
|
||||
./peano.go
|
||||
./printbig.go
|
||||
./range.go
|
||||
./recover.go
|
||||
./recover1.go
|
||||
./recover2.go
|
||||
# ./recover3.go # fail
|
||||
./rename.go
|
||||
./rename1.go
|
||||
./runtime.go
|
||||
./sieve.go
|
||||
./sigchld.go
|
||||
./simassign.go
|
||||
./sinit.go
|
||||
./stack.go
|
||||
./string_lit.go
|
||||
./stringrange.go
|
||||
./switch.go
|
||||
./switch1.go
|
||||
./test0.go
|
||||
./turing.go
|
||||
./typeswitch.go
|
||||
./typeswitch1.go
|
||||
./typeswitch2.go
|
||||
./undef.go
|
||||
./utf.go
|
||||
./varerr.go
|
||||
./varinit.go
|
||||
./vectors.go
|
||||
./zerodivide.go
|
||||
ken/array.go
|
||||
ken/chan.go
|
||||
ken/chan1.go
|
||||
ken/complit.go
|
||||
# ken/cplx0.go # output fail
|
||||
# ken/cplx1.go # fail
|
||||
# ken/cplx2.go # fail
|
||||
# ken/cplx3.go # output fail
|
||||
# ken/cplx4.go # fail, BUG
|
||||
# ken/cplx5.go # output fail
|
||||
ken/divconst.go
|
||||
ken/divmod.go
|
||||
ken/embed.go
|
||||
ken/for.go
|
||||
ken/interbasic.go
|
||||
ken/interfun.go
|
||||
ken/intervar.go
|
||||
ken/label.go
|
||||
ken/litfun.go
|
||||
ken/mfunc.go
|
||||
ken/modconst.go
|
||||
ken/ptrfun.go
|
||||
ken/ptrvar.go
|
||||
ken/range.go
|
||||
ken/rob1.go
|
||||
ken/rob2.go
|
||||
ken/robfor.go
|
||||
ken/robfunc.go
|
||||
ken/robif.go
|
||||
ken/shift.go
|
||||
ken/simparray.go
|
||||
ken/simpbool.go
|
||||
ken/simpconv.go
|
||||
ken/simpfun.go
|
||||
ken/simpprint.go
|
||||
ken/simpswitch.go
|
||||
ken/simpvar.go
|
||||
ken/slicearray.go
|
||||
ken/sliceslice.go
|
||||
ken/string.go
|
||||
ken/strvar.go
|
||||
chan/doubleselect.go
|
||||
chan/fifo.go
|
||||
chan/goroutines.go
|
||||
chan/nonblock.go
|
||||
chan/perm.go
|
||||
chan/powser1.go
|
||||
chan/powser2.go
|
||||
chan/select.go
|
||||
chan/select2.go
|
||||
# chan/select3.go # fail
|
||||
chan/sieve1.go
|
||||
chan/sieve2.go
|
||||
interface/bigdata.go
|
||||
interface/convert.go
|
||||
interface/convert1.go
|
||||
interface/convert2.go
|
||||
interface/embed.go
|
||||
interface/embed0.go
|
||||
interface/embed1.go
|
||||
interface/explicit.go
|
||||
interface/fail.go
|
||||
interface/fake.go
|
||||
interface/pointer.go
|
||||
interface/receiver.go
|
||||
interface/receiver1.go
|
||||
interface/recursive.go
|
||||
interface/returntype.go
|
||||
interface/struct.go
|
||||
nilptr/arrayindex.go
|
||||
nilptr/arrayindex1.go
|
||||
nilptr/arraytoslice.go
|
||||
nilptr/arraytoslice1.go
|
||||
nilptr/arraytoslice2.go
|
||||
nilptr/slicearray.go
|
||||
nilptr/structfield.go
|
||||
nilptr/structfield1.go
|
||||
nilptr/structfield2.go
|
||||
nilptr/structfieldaddr.go
|
||||
syntax/forvar.go
|
||||
syntax/import.go
|
||||
syntax/interface.go
|
||||
syntax/semi1.go
|
||||
syntax/semi2.go
|
||||
syntax/semi3.go
|
||||
syntax/semi4.go
|
||||
syntax/semi5.go
|
||||
syntax/semi6.go
|
||||
syntax/semi7.go
|
||||
syntax/slice.go
|
||||
syntax/topexpr.go
|
||||
syntax/vareq.go
|
||||
syntax/vareq1.go
|
||||
fixedbugs/bug000.go
|
||||
fixedbugs/bug001.go
|
||||
fixedbugs/bug002.go
|
||||
fixedbugs/bug003.go
|
||||
fixedbugs/bug004.go
|
||||
fixedbugs/bug005.go
|
||||
fixedbugs/bug006.go
|
||||
fixedbugs/bug007.go
|
||||
fixedbugs/bug008.go
|
||||
fixedbugs/bug009.go
|
||||
fixedbugs/bug010.go
|
||||
fixedbugs/bug011.go
|
||||
fixedbugs/bug012.go
|
||||
fixedbugs/bug013.go
|
||||
fixedbugs/bug014.go
|
||||
fixedbugs/bug015.go
|
||||
fixedbugs/bug016.go
|
||||
fixedbugs/bug017.go
|
||||
fixedbugs/bug020.go
|
||||
fixedbugs/bug021.go
|
||||
fixedbugs/bug022.go
|
||||
fixedbugs/bug023.go
|
||||
fixedbugs/bug024.go
|
||||
fixedbugs/bug026.go
|
||||
fixedbugs/bug027.go
|
||||
fixedbugs/bug028.go
|
||||
fixedbugs/bug030.go
|
||||
fixedbugs/bug031.go
|
||||
fixedbugs/bug035.go
|
||||
fixedbugs/bug036.go
|
||||
fixedbugs/bug037.go
|
||||
fixedbugs/bug038.go
|
||||
fixedbugs/bug039.go
|
||||
fixedbugs/bug040.go
|
||||
fixedbugs/bug045.go
|
||||
fixedbugs/bug046.go
|
||||
fixedbugs/bug047.go
|
||||
fixedbugs/bug048.go
|
||||
fixedbugs/bug049.go
|
||||
fixedbugs/bug050.go
|
||||
fixedbugs/bug051.go
|
||||
fixedbugs/bug052.go
|
||||
fixedbugs/bug053.go
|
||||
fixedbugs/bug054.go
|
||||
fixedbugs/bug055.go
|
||||
fixedbugs/bug056.go
|
||||
fixedbugs/bug057.go
|
||||
fixedbugs/bug058.go
|
||||
fixedbugs/bug059.go
|
||||
fixedbugs/bug060.go
|
||||
fixedbugs/bug061.go
|
||||
fixedbugs/bug062.go
|
||||
fixedbugs/bug063.go
|
||||
fixedbugs/bug064.go
|
||||
fixedbugs/bug065.go
|
||||
fixedbugs/bug066.go
|
||||
fixedbugs/bug067.go
|
||||
fixedbugs/bug068.go
|
||||
fixedbugs/bug069.go
|
||||
fixedbugs/bug070.go
|
||||
fixedbugs/bug071.go
|
||||
fixedbugs/bug072.go
|
||||
fixedbugs/bug073.go
|
||||
fixedbugs/bug074.go
|
||||
fixedbugs/bug075.go
|
||||
fixedbugs/bug076.go
|
||||
fixedbugs/bug077.go
|
||||
fixedbugs/bug078.go
|
||||
fixedbugs/bug080.go
|
||||
fixedbugs/bug081.go
|
||||
fixedbugs/bug082.go
|
||||
fixedbugs/bug083.go
|
||||
fixedbugs/bug084.go
|
||||
fixedbugs/bug085.go
|
||||
fixedbugs/bug086.go
|
||||
fixedbugs/bug087.go
|
||||
fixedbugs/bug088.go
|
||||
fixedbugs/bug089.go
|
||||
fixedbugs/bug090.go
|
||||
fixedbugs/bug091.go
|
||||
fixedbugs/bug092.go
|
||||
fixedbugs/bug093.go
|
||||
fixedbugs/bug094.go
|
||||
fixedbugs/bug096.go
|
||||
fixedbugs/bug097.go
|
||||
fixedbugs/bug098.go
|
||||
fixedbugs/bug099.go
|
||||
fixedbugs/bug101.go
|
||||
fixedbugs/bug102.go
|
||||
fixedbugs/bug103.go
|
||||
fixedbugs/bug104.go
|
||||
fixedbugs/bug106.go
|
||||
fixedbugs/bug107.go
|
||||
fixedbugs/bug108.go
|
||||
fixedbugs/bug109.go
|
||||
fixedbugs/bug110.go
|
||||
fixedbugs/bug111.go
|
||||
fixedbugs/bug112.go
|
||||
fixedbugs/bug113.go
|
||||
fixedbugs/bug114.go
|
||||
fixedbugs/bug115.go
|
||||
fixedbugs/bug116.go
|
||||
fixedbugs/bug117.go
|
||||
fixedbugs/bug118.go
|
||||
fixedbugs/bug119.go
|
||||
fixedbugs/bug120.go
|
||||
fixedbugs/bug121.go
|
||||
fixedbugs/bug122.go
|
||||
fixedbugs/bug123.go
|
||||
fixedbugs/bug126.go
|
||||
fixedbugs/bug127.go
|
||||
fixedbugs/bug128.go
|
||||
fixedbugs/bug129.go
|
||||
fixedbugs/bug130.go
|
||||
fixedbugs/bug131.go
|
||||
fixedbugs/bug132.go
|
||||
fixedbugs/bug133.go
|
||||
fixedbugs/bug135.go
|
||||
fixedbugs/bug136.go
|
||||
fixedbugs/bug137.go
|
||||
fixedbugs/bug139.go
|
||||
fixedbugs/bug140.go
|
||||
fixedbugs/bug141.go
|
||||
fixedbugs/bug142.go
|
||||
fixedbugs/bug143.go
|
||||
fixedbugs/bug144.go
|
||||
fixedbugs/bug145.go
|
||||
fixedbugs/bug146.go
|
||||
fixedbugs/bug147.go
|
||||
fixedbugs/bug148.go
|
||||
fixedbugs/bug149.go
|
||||
fixedbugs/bug150.go
|
||||
fixedbugs/bug151.go
|
||||
fixedbugs/bug152.go
|
||||
fixedbugs/bug154.go
|
||||
fixedbugs/bug155.go
|
||||
fixedbugs/bug156.go
|
||||
fixedbugs/bug157.go
|
||||
fixedbugs/bug158.go
|
||||
fixedbugs/bug159.go
|
||||
fixedbugs/bug160.go
|
||||
fixedbugs/bug161.go
|
||||
fixedbugs/bug163.go
|
||||
fixedbugs/bug164.go
|
||||
fixedbugs/bug165.go
|
||||
fixedbugs/bug167.go
|
||||
fixedbugs/bug168.go
|
||||
fixedbugs/bug169.go
|
||||
fixedbugs/bug170.go
|
||||
fixedbugs/bug171.go
|
||||
fixedbugs/bug172.go
|
||||
fixedbugs/bug173.go
|
||||
fixedbugs/bug174.go
|
||||
fixedbugs/bug175.go
|
||||
fixedbugs/bug176.go
|
||||
fixedbugs/bug177.go
|
||||
fixedbugs/bug178.go
|
||||
fixedbugs/bug179.go
|
||||
fixedbugs/bug180.go
|
||||
fixedbugs/bug181.go
|
||||
fixedbugs/bug182.go
|
||||
fixedbugs/bug183.go
|
||||
fixedbugs/bug184.go
|
||||
fixedbugs/bug185.go
|
||||
fixedbugs/bug186.go
|
||||
fixedbugs/bug187.go
|
||||
fixedbugs/bug188.go
|
||||
fixedbugs/bug189.go
|
||||
fixedbugs/bug190.go
|
||||
fixedbugs/bug191.go
|
||||
fixedbugs/bug192.go
|
||||
fixedbugs/bug193.go
|
||||
fixedbugs/bug194.go
|
||||
fixedbugs/bug195.go
|
||||
fixedbugs/bug196.go
|
||||
fixedbugs/bug197.go
|
||||
fixedbugs/bug198.go
|
||||
fixedbugs/bug199.go
|
||||
fixedbugs/bug200.go
|
||||
fixedbugs/bug201.go
|
||||
fixedbugs/bug202.go
|
||||
fixedbugs/bug203.go
|
||||
fixedbugs/bug204.go
|
||||
fixedbugs/bug205.go
|
||||
fixedbugs/bug206.go
|
||||
fixedbugs/bug207.go
|
||||
fixedbugs/bug208.go
|
||||
fixedbugs/bug209.go
|
||||
fixedbugs/bug211.go
|
||||
fixedbugs/bug212.go
|
||||
fixedbugs/bug213.go
|
||||
fixedbugs/bug214.go
|
||||
fixedbugs/bug215.go
|
||||
fixedbugs/bug216.go
|
||||
fixedbugs/bug217.go
|
||||
fixedbugs/bug218.go
|
||||
fixedbugs/bug219.go
|
||||
fixedbugs/bug220.go
|
||||
fixedbugs/bug221.go
|
||||
fixedbugs/bug222.go
|
||||
fixedbugs/bug223.go
|
||||
fixedbugs/bug224.go
|
||||
fixedbugs/bug225.go
|
||||
fixedbugs/bug226.go
|
||||
fixedbugs/bug227.go
|
||||
fixedbugs/bug228.go
|
||||
fixedbugs/bug229.go
|
||||
fixedbugs/bug230.go
|
||||
fixedbugs/bug231.go
|
||||
fixedbugs/bug232.go
|
||||
fixedbugs/bug233.go
|
||||
fixedbugs/bug234.go
|
||||
fixedbugs/bug235.go
|
||||
fixedbugs/bug236.go
|
||||
fixedbugs/bug237.go
|
||||
fixedbugs/bug238.go
|
||||
fixedbugs/bug239.go
|
||||
fixedbugs/bug240.go
|
||||
fixedbugs/bug241.go
|
||||
fixedbugs/bug242.go
|
||||
# fixedbugs/bug243.go # fail, flaky on android build
|
||||
fixedbugs/bug244.go
|
||||
fixedbugs/bug245.go
|
||||
fixedbugs/bug246.go
|
||||
fixedbugs/bug247.go
|
||||
fixedbugs/bug248.go
|
||||
fixedbugs/bug249.go
|
||||
fixedbugs/bug250.go
|
||||
fixedbugs/bug251.go
|
||||
fixedbugs/bug252.go
|
||||
fixedbugs/bug253.go
|
||||
fixedbugs/bug254.go
|
||||
fixedbugs/bug255.go
|
||||
fixedbugs/bug256.go
|
||||
fixedbugs/bug257.go
|
||||
fixedbugs/bug258.go
|
||||
fixedbugs/bug259.go
|
||||
fixedbugs/bug261.go
|
||||
fixedbugs/bug262.go
|
||||
fixedbugs/bug263.go
|
||||
fixedbugs/bug264.go
|
||||
fixedbugs/bug265.go
|
||||
fixedbugs/bug266.go
|
||||
fixedbugs/bug267.go
|
||||
fixedbugs/bug268.go
|
||||
fixedbugs/bug269.go
|
||||
fixedbugs/bug270.go
|
||||
fixedbugs/bug271.go
|
||||
fixedbugs/bug272.go
|
||||
fixedbugs/bug273.go
|
||||
fixedbugs/bug274.go
|
||||
fixedbugs/bug275.go
|
||||
fixedbugs/bug276.go
|
||||
fixedbugs/bug277.go
|
||||
fixedbugs/bug278.go
|
||||
fixedbugs/bug279.go
|
||||
fixedbugs/bug280.go
|
||||
fixedbugs/bug281.go
|
||||
fixedbugs/bug282.go
|
||||
fixedbugs/bug283.go
|
||||
fixedbugs/bug284.go
|
||||
fixedbugs/bug285.go
|
||||
fixedbugs/bug286.go
|
||||
fixedbugs/bug287.go
|
||||
fixedbugs/bug288.go
|
||||
fixedbugs/bug289.go
|
||||
fixedbugs/bug290.go
|
||||
fixedbugs/bug291.go
|
||||
fixedbugs/bug292.go
|
||||
fixedbugs/bug293.go
|
||||
fixedbugs/bug294.go
|
||||
fixedbugs/bug295.go
|
||||
fixedbugs/bug296.go
|
||||
fixedbugs/bug297.go
|
||||
fixedbugs/bug298.go
|
||||
# bugs/bug260.go # fail, BUG
|
|
@ -0,0 +1,53 @@
|
|||
// errchk $G -e $D/$F.go
|
||||
|
||||
// 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.
|
||||
|
||||
package main
|
||||
|
||||
import "sync"
|
||||
|
||||
type T struct {
|
||||
int
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
func main() {
|
||||
{
|
||||
var x, y sync.Mutex
|
||||
x = y // ERROR "assignment.*Mutex"
|
||||
_ = x
|
||||
}
|
||||
{
|
||||
var x, y T
|
||||
x = y // ERROR "assignment.*Mutex"
|
||||
_ = x
|
||||
}
|
||||
{
|
||||
var x, y [2]sync.Mutex
|
||||
x = y // ERROR "assignment.*Mutex"
|
||||
_ = x
|
||||
}
|
||||
{
|
||||
var x, y [2]T
|
||||
x = y // ERROR "assignment.*Mutex"
|
||||
_ = x
|
||||
}
|
||||
{
|
||||
x := sync.Mutex{0, 0} // ERROR "assignment.*Mutex"
|
||||
_ = x
|
||||
}
|
||||
{
|
||||
x := sync.Mutex{key: 0} // ERROR "(unknown|assignment).*Mutex"
|
||||
_ = x
|
||||
}
|
||||
{
|
||||
x := &sync.Mutex{} // ok
|
||||
var y sync.Mutex // ok
|
||||
y = *x // ERROR "assignment.*Mutex"
|
||||
*x = y // ERROR "assignment.*Mutex"
|
||||
_ = x
|
||||
_ = y
|
||||
}
|
||||
}
|
|
@ -0,0 +1,343 @@
|
|||
// errchk $G -e $D/$F.go
|
||||
|
||||
// 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.
|
||||
|
||||
package main
|
||||
|
||||
type (
|
||||
A [10]int
|
||||
B []int
|
||||
C chan int
|
||||
F func() int
|
||||
I interface {
|
||||
m() int
|
||||
}
|
||||
M map[int]int
|
||||
P *int
|
||||
S struct {
|
||||
X int
|
||||
}
|
||||
|
||||
A1 [10]int
|
||||
B1 []int
|
||||
C1 chan int
|
||||
F1 func() int
|
||||
I1 interface {
|
||||
m() int
|
||||
}
|
||||
M1 map[int]int
|
||||
P1 *int
|
||||
S1 struct {
|
||||
X int
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
a0 [10]int
|
||||
b0 []int
|
||||
c0 chan int
|
||||
f0 func() int
|
||||
i0 interface {
|
||||
m() int
|
||||
}
|
||||
m0 map[int]int
|
||||
p0 *int
|
||||
s0 struct {
|
||||
X int
|
||||
}
|
||||
|
||||
a A
|
||||
b B
|
||||
c C
|
||||
f F
|
||||
i I
|
||||
m M
|
||||
p P
|
||||
s S
|
||||
|
||||
a1 A1
|
||||
b1 B1
|
||||
c1 C1
|
||||
f1 F1
|
||||
i1 I1
|
||||
m1 M1
|
||||
p1 P1
|
||||
s1 S1
|
||||
|
||||
pa0 *[10]int
|
||||
pb0 *[]int
|
||||
pc0 *chan int
|
||||
pf0 *func() int
|
||||
pi0 *interface {
|
||||
m() int
|
||||
}
|
||||
pm0 *map[int]int
|
||||
pp0 **int
|
||||
ps0 *struct {
|
||||
X int
|
||||
}
|
||||
|
||||
pa *A
|
||||
pb *B
|
||||
pc *C
|
||||
pf *F
|
||||
pi *I
|
||||
pm *M
|
||||
pp *P
|
||||
ps *S
|
||||
|
||||
pa1 *A1
|
||||
pb1 *B1
|
||||
pc1 *C1
|
||||
pf1 *F1
|
||||
pi1 *I1
|
||||
pm1 *M1
|
||||
pp1 *P1
|
||||
ps1 *S1
|
||||
)
|
||||
|
||||
func main() {
|
||||
a0 = a
|
||||
a0 = a1
|
||||
a = a0
|
||||
a = a1 // ERROR "cannot use"
|
||||
a1 = a0
|
||||
a1 = a // ERROR "cannot use"
|
||||
|
||||
b0 = b
|
||||
b0 = b1
|
||||
b = b0
|
||||
b = b1 // ERROR "cannot use"
|
||||
b1 = b0
|
||||
b1 = b // ERROR "cannot use"
|
||||
|
||||
c0 = c
|
||||
c0 = c1
|
||||
c = c0
|
||||
c = c1 // ERROR "cannot use"
|
||||
c1 = c0
|
||||
c1 = c // ERROR "cannot use"
|
||||
|
||||
f0 = f
|
||||
f0 = f1
|
||||
f = f0
|
||||
f = f1 // ERROR "cannot use"
|
||||
f1 = f0
|
||||
f1 = f // ERROR "cannot use"
|
||||
|
||||
i0 = i
|
||||
i0 = i1
|
||||
i = i0
|
||||
i = i1
|
||||
i1 = i0
|
||||
i1 = i
|
||||
|
||||
m0 = m
|
||||
m0 = m1
|
||||
m = m0
|
||||
m = m1 // ERROR "cannot use"
|
||||
m1 = m0
|
||||
m1 = m // ERROR "cannot use"
|
||||
|
||||
p0 = p
|
||||
p0 = p1
|
||||
p = p0
|
||||
p = p1 // ERROR "cannot use"
|
||||
p1 = p0
|
||||
p1 = p // ERROR "cannot use"
|
||||
|
||||
s0 = s
|
||||
s0 = s1
|
||||
s = s0
|
||||
s = s1 // ERROR "cannot use"
|
||||
s1 = s0
|
||||
s1 = s // ERROR "cannot use"
|
||||
|
||||
pa0 = pa // ERROR "cannot use|incompatible"
|
||||
pa0 = pa1 // ERROR "cannot use|incompatible"
|
||||
pa = pa0 // ERROR "cannot use|incompatible"
|
||||
pa = pa1 // ERROR "cannot use|incompatible"
|
||||
pa1 = pa0 // ERROR "cannot use|incompatible"
|
||||
pa1 = pa // ERROR "cannot use|incompatible"
|
||||
|
||||
pb0 = pb // ERROR "cannot use|incompatible"
|
||||
pb0 = pb1 // ERROR "cannot use|incompatible"
|
||||
pb = pb0 // ERROR "cannot use|incompatible"
|
||||
pb = pb1 // ERROR "cannot use|incompatible"
|
||||
pb1 = pb0 // ERROR "cannot use|incompatible"
|
||||
pb1 = pb // ERROR "cannot use|incompatible"
|
||||
|
||||
pc0 = pc // ERROR "cannot use|incompatible"
|
||||
pc0 = pc1 // ERROR "cannot use|incompatible"
|
||||
pc = pc0 // ERROR "cannot use|incompatible"
|
||||
pc = pc1 // ERROR "cannot use|incompatible"
|
||||
pc1 = pc0 // ERROR "cannot use|incompatible"
|
||||
pc1 = pc // ERROR "cannot use|incompatible"
|
||||
|
||||
pf0 = pf // ERROR "cannot use|incompatible"
|
||||
pf0 = pf1 // ERROR "cannot use|incompatible"
|
||||
pf = pf0 // ERROR "cannot use|incompatible"
|
||||
pf = pf1 // ERROR "cannot use|incompatible"
|
||||
pf1 = pf0 // ERROR "cannot use|incompatible"
|
||||
pf1 = pf // ERROR "cannot use|incompatible"
|
||||
|
||||
pi0 = pi // ERROR "cannot use|incompatible"
|
||||
pi0 = pi1 // ERROR "cannot use|incompatible"
|
||||
pi = pi0 // ERROR "cannot use|incompatible"
|
||||
pi = pi1 // ERROR "cannot use|incompatible"
|
||||
pi1 = pi0 // ERROR "cannot use|incompatible"
|
||||
pi1 = pi // ERROR "cannot use|incompatible"
|
||||
|
||||
pm0 = pm // ERROR "cannot use|incompatible"
|
||||
pm0 = pm1 // ERROR "cannot use|incompatible"
|
||||
pm = pm0 // ERROR "cannot use|incompatible"
|
||||
pm = pm1 // ERROR "cannot use|incompatible"
|
||||
pm1 = pm0 // ERROR "cannot use|incompatible"
|
||||
pm1 = pm // ERROR "cannot use|incompatible"
|
||||
|
||||
pp0 = pp // ERROR "cannot use|incompatible"
|
||||
pp0 = pp1 // ERROR "cannot use|incompatible"
|
||||
pp = pp0 // ERROR "cannot use|incompatible"
|
||||
pp = pp1 // ERROR "cannot use|incompatible"
|
||||
pp1 = pp0 // ERROR "cannot use|incompatible"
|
||||
pp1 = pp // ERROR "cannot use|incompatible"
|
||||
|
||||
ps0 = ps // ERROR "cannot use|incompatible"
|
||||
ps0 = ps1 // ERROR "cannot use|incompatible"
|
||||
ps = ps0 // ERROR "cannot use|incompatible"
|
||||
ps = ps1 // ERROR "cannot use|incompatible"
|
||||
ps1 = ps0 // ERROR "cannot use|incompatible"
|
||||
ps1 = ps // ERROR "cannot use|incompatible"
|
||||
|
||||
|
||||
a0 = [10]int(a)
|
||||
a0 = [10]int(a1)
|
||||
a = A(a0)
|
||||
a = A(a1)
|
||||
a1 = A1(a0)
|
||||
a1 = A1(a)
|
||||
|
||||
b0 = []int(b)
|
||||
b0 = []int(b1)
|
||||
b = B(b0)
|
||||
b = B(b1)
|
||||
b1 = B1(b0)
|
||||
b1 = B1(b)
|
||||
|
||||
c0 = chan int(c)
|
||||
c0 = chan int(c1)
|
||||
c = C(c0)
|
||||
c = C(c1)
|
||||
c1 = C1(c0)
|
||||
c1 = C1(c)
|
||||
|
||||
f0 = func() int(f)
|
||||
f0 = func() int(f1)
|
||||
f = F(f0)
|
||||
f = F(f1)
|
||||
f1 = F1(f0)
|
||||
f1 = F1(f)
|
||||
|
||||
i0 = interface {
|
||||
m() int
|
||||
}(i)
|
||||
i0 = interface {
|
||||
m() int
|
||||
}(i1)
|
||||
i = I(i0)
|
||||
i = I(i1)
|
||||
i1 = I1(i0)
|
||||
i1 = I1(i)
|
||||
|
||||
m0 = map[int]int(m)
|
||||
m0 = map[int]int(m1)
|
||||
m = M(m0)
|
||||
m = M(m1)
|
||||
m1 = M1(m0)
|
||||
m1 = M1(m)
|
||||
|
||||
p0 = (*int)(p)
|
||||
p0 = (*int)(p1)
|
||||
p = P(p0)
|
||||
p = P(p1)
|
||||
p1 = P1(p0)
|
||||
p1 = P1(p)
|
||||
|
||||
s0 = struct {
|
||||
X int
|
||||
}(s)
|
||||
s0 = struct {
|
||||
X int
|
||||
}(s1)
|
||||
s = S(s0)
|
||||
s = S(s1)
|
||||
s1 = S1(s0)
|
||||
s1 = S1(s)
|
||||
|
||||
pa0 = (*[10]int)(pa)
|
||||
pa0 = (*[10]int)(pa1)
|
||||
pa = (*A)(pa0)
|
||||
pa = (*A)(pa1)
|
||||
pa1 = (*A1)(pa0)
|
||||
pa1 = (*A1)(pa)
|
||||
|
||||
pb0 = (*[]int)(pb)
|
||||
pb0 = (*[]int)(pb1)
|
||||
pb = (*B)(pb0)
|
||||
pb = (*B)(pb1)
|
||||
pb1 = (*B1)(pb0)
|
||||
pb1 = (*B1)(pb)
|
||||
|
||||
pc0 = (*chan int)(pc)
|
||||
pc0 = (*chan int)(pc1)
|
||||
pc = (*C)(pc0)
|
||||
pc = (*C)(pc1)
|
||||
pc1 = (*C1)(pc0)
|
||||
pc1 = (*C1)(pc)
|
||||
|
||||
pf0 = (*func() int)(pf)
|
||||
pf0 = (*func() int)(pf1)
|
||||
pf = (*F)(pf0)
|
||||
pf = (*F)(pf1)
|
||||
pf1 = (*F1)(pf0)
|
||||
pf1 = (*F1)(pf)
|
||||
|
||||
pi0 = (*interface {
|
||||
m() int
|
||||
})(pi)
|
||||
pi0 = (*interface {
|
||||
m() int
|
||||
})(pi1)
|
||||
pi = (*I)(pi0)
|
||||
pi = (*I)(pi1)
|
||||
pi1 = (*I1)(pi0)
|
||||
pi1 = (*I1)(pi)
|
||||
|
||||
pm0 = (*map[int]int)(pm)
|
||||
pm0 = (*map[int]int)(pm1)
|
||||
pm = (*M)(pm0)
|
||||
pm = (*M)(pm1)
|
||||
pm1 = (*M1)(pm0)
|
||||
pm1 = (*M1)(pm)
|
||||
|
||||
pp0 = (**int)(pp)
|
||||
pp0 = (**int)(pp1)
|
||||
pp = (*P)(pp0)
|
||||
pp = (*P)(pp1)
|
||||
pp1 = (*P1)(pp0)
|
||||
pp1 = (*P1)(pp)
|
||||
|
||||
ps0 = (*struct {
|
||||
X int
|
||||
})(ps)
|
||||
ps0 = (*struct {
|
||||
X int
|
||||
})(ps1)
|
||||
ps = (*S)(ps0)
|
||||
ps = (*S)(ps1)
|
||||
ps1 = (*S1)(ps0)
|
||||
ps1 = (*S1)(ps)
|
||||
|
||||
}
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
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 "The Computer Language Benchmarks Game" nor the
|
||||
name of "The Computer Language Shootout Benchmarks" 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.
|
||||
*/
|
||||
|
||||
/* The Computer Language Benchmarks Game
|
||||
* http://shootout.alioth.debian.org/
|
||||
*
|
||||
* contributed by The Go Authors.
|
||||
* based on C program by Kevin Carson
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var n = flag.Int("n", 15, "depth")
|
||||
|
||||
type Node struct {
|
||||
item int
|
||||
left, right *Node
|
||||
}
|
||||
|
||||
type Arena struct {
|
||||
head *Node
|
||||
}
|
||||
|
||||
var arena Arena
|
||||
|
||||
func (n *Node) free() {
|
||||
if n.left != nil {
|
||||
n.left.free()
|
||||
}
|
||||
if n.right != nil {
|
||||
n.right.free()
|
||||
}
|
||||
n.left = arena.head
|
||||
arena.head = n
|
||||
}
|
||||
|
||||
func (a *Arena) New(item int, left, right *Node) *Node {
|
||||
if a.head == nil {
|
||||
nodes := make([]Node, 3<<uint(*n))
|
||||
for i := 0; i < len(nodes)-1; i++ {
|
||||
nodes[i].left = &nodes[i+1]
|
||||
}
|
||||
a.head = &nodes[0]
|
||||
}
|
||||
n := a.head
|
||||
a.head = a.head.left
|
||||
n.item = item
|
||||
n.left = left
|
||||
n.right = right
|
||||
return n
|
||||
}
|
||||
|
||||
func bottomUpTree(item, depth int) *Node {
|
||||
if depth <= 0 {
|
||||
return arena.New(item, nil, nil)
|
||||
}
|
||||
return arena.New(item, bottomUpTree(2*item-1, depth-1), bottomUpTree(2*item, depth-1))
|
||||
}
|
||||
|
||||
func (n *Node) itemCheck() int {
|
||||
if n.left == nil {
|
||||
return n.item
|
||||
}
|
||||
return n.item + n.left.itemCheck() - n.right.itemCheck()
|
||||
}
|
||||
|
||||
const minDepth = 4
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
maxDepth := *n
|
||||
if minDepth+2 > *n {
|
||||
maxDepth = minDepth + 2
|
||||
}
|
||||
stretchDepth := maxDepth + 1
|
||||
|
||||
check := bottomUpTree(0, stretchDepth).itemCheck()
|
||||
fmt.Printf("stretch tree of depth %d\t check: %d\n", stretchDepth, check)
|
||||
|
||||
longLivedTree := bottomUpTree(0, maxDepth)
|
||||
|
||||
for depth := minDepth; depth <= maxDepth; depth += 2 {
|
||||
iterations := 1 << uint(maxDepth-depth+minDepth)
|
||||
check = 0
|
||||
|
||||
for i := 1; i <= iterations; i++ {
|
||||
t := bottomUpTree(i, depth)
|
||||
check += t.itemCheck()
|
||||
t.free()
|
||||
t = bottomUpTree(-i, depth)
|
||||
check += t.itemCheck()
|
||||
t.free()
|
||||
}
|
||||
fmt.Printf("%d\t trees of depth %d\t check: %d\n", iterations*2, depth, check)
|
||||
}
|
||||
fmt.Printf("long lived tree of depth %d\t check: %d\n", maxDepth, longLivedTree.itemCheck())
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
stretch tree of depth 16 check: -1
|
||||
65536 trees of depth 4 check: -65536
|
||||
16384 trees of depth 6 check: -16384
|
||||
4096 trees of depth 8 check: -4096
|
||||
1024 trees of depth 10 check: -1024
|
||||
256 trees of depth 12 check: -256
|
||||
64 trees of depth 14 check: -64
|
||||
long lived tree of depth 15 check: -1
|
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
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 "The Computer Language Benchmarks Game" nor the
|
||||
name of "The Computer Language Shootout Benchmarks" 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.
|
||||
*/
|
||||
|
||||
/* The Computer Language Shootout Benchmarks
|
||||
http://shootout.alioth.debian.org/
|
||||
|
||||
contributed by Kevin Carson
|
||||
compilation:
|
||||
gcc -O3 -fomit-frame-pointer -funroll-loops -static binary-trees.c -lm
|
||||
icc -O3 -ip -unroll -static binary-trees.c -lm
|
||||
*/
|
||||
|
||||
#include <malloc.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
typedef struct tn {
|
||||
struct tn* left;
|
||||
struct tn* right;
|
||||
long item;
|
||||
} treeNode;
|
||||
|
||||
|
||||
treeNode* NewTreeNode(treeNode* left, treeNode* right, long item)
|
||||
{
|
||||
treeNode* new;
|
||||
|
||||
new = (treeNode*)malloc(sizeof(treeNode));
|
||||
|
||||
new->left = left;
|
||||
new->right = right;
|
||||
new->item = item;
|
||||
|
||||
return new;
|
||||
} /* NewTreeNode() */
|
||||
|
||||
|
||||
long ItemCheck(treeNode* tree)
|
||||
{
|
||||
if (tree->left == NULL)
|
||||
return tree->item;
|
||||
else
|
||||
return tree->item + ItemCheck(tree->left) - ItemCheck(tree->right);
|
||||
} /* ItemCheck() */
|
||||
|
||||
|
||||
treeNode* BottomUpTree(long item, unsigned depth)
|
||||
{
|
||||
if (depth > 0)
|
||||
return NewTreeNode
|
||||
(
|
||||
BottomUpTree(2 * item - 1, depth - 1),
|
||||
BottomUpTree(2 * item, depth - 1),
|
||||
item
|
||||
);
|
||||
else
|
||||
return NewTreeNode(NULL, NULL, item);
|
||||
} /* BottomUpTree() */
|
||||
|
||||
|
||||
void DeleteTree(treeNode* tree)
|
||||
{
|
||||
if (tree->left != NULL)
|
||||
{
|
||||
DeleteTree(tree->left);
|
||||
DeleteTree(tree->right);
|
||||
}
|
||||
|
||||
free(tree);
|
||||
} /* DeleteTree() */
|
||||
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
unsigned N, depth, minDepth, maxDepth, stretchDepth;
|
||||
treeNode *stretchTree, *longLivedTree, *tempTree;
|
||||
|
||||
N = atol(argv[1]);
|
||||
|
||||
minDepth = 4;
|
||||
|
||||
if ((minDepth + 2) > N)
|
||||
maxDepth = minDepth + 2;
|
||||
else
|
||||
maxDepth = N;
|
||||
|
||||
stretchDepth = maxDepth + 1;
|
||||
|
||||
stretchTree = BottomUpTree(0, stretchDepth);
|
||||
printf
|
||||
(
|
||||
"stretch tree of depth %u\t check: %li\n",
|
||||
stretchDepth,
|
||||
ItemCheck(stretchTree)
|
||||
);
|
||||
|
||||
DeleteTree(stretchTree);
|
||||
|
||||
longLivedTree = BottomUpTree(0, maxDepth);
|
||||
|
||||
for (depth = minDepth; depth <= maxDepth; depth += 2)
|
||||
{
|
||||
long i, iterations, check;
|
||||
|
||||
iterations = pow(2, maxDepth - depth + minDepth);
|
||||
|
||||
check = 0;
|
||||
|
||||
for (i = 1; i <= iterations; i++)
|
||||
{
|
||||
tempTree = BottomUpTree(i, depth);
|
||||
check += ItemCheck(tempTree);
|
||||
DeleteTree(tempTree);
|
||||
|
||||
tempTree = BottomUpTree(-i, depth);
|
||||
check += ItemCheck(tempTree);
|
||||
DeleteTree(tempTree);
|
||||
} /* for(i = 1...) */
|
||||
|
||||
printf
|
||||
(
|
||||
"%li\t trees of depth %u\t check: %li\n",
|
||||
iterations * 2,
|
||||
depth,
|
||||
check
|
||||
);
|
||||
} /* for(depth = minDepth...) */
|
||||
|
||||
printf
|
||||
(
|
||||
"long lived tree of depth %u\t check: %li\n",
|
||||
maxDepth,
|
||||
ItemCheck(longLivedTree)
|
||||
);
|
||||
|
||||
return 0;
|
||||
} /* main() */
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
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 "The Computer Language Benchmarks Game" nor the
|
||||
name of "The Computer Language Shootout Benchmarks" 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.
|
||||
*/
|
||||
|
||||
/* The Computer Language Benchmarks Game
|
||||
* http://shootout.alioth.debian.org/
|
||||
*
|
||||
* contributed by The Go Authors.
|
||||
* based on C program by Kevin Carson
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var n = flag.Int("n", 15, "depth")
|
||||
|
||||
type Node struct {
|
||||
item int
|
||||
left, right *Node
|
||||
}
|
||||
|
||||
func bottomUpTree(item, depth int) *Node {
|
||||
if depth <= 0 {
|
||||
return &Node{item: item}
|
||||
}
|
||||
return &Node{item, bottomUpTree(2*item-1, depth-1), bottomUpTree(2*item, depth-1)}
|
||||
}
|
||||
|
||||
func (n *Node) itemCheck() int {
|
||||
if n.left == nil {
|
||||
return n.item
|
||||
}
|
||||
return n.item + n.left.itemCheck() - n.right.itemCheck()
|
||||
}
|
||||
|
||||
const minDepth = 4
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
maxDepth := *n
|
||||
if minDepth+2 > *n {
|
||||
maxDepth = minDepth + 2
|
||||
}
|
||||
stretchDepth := maxDepth + 1
|
||||
|
||||
check := bottomUpTree(0, stretchDepth).itemCheck()
|
||||
fmt.Printf("stretch tree of depth %d\t check: %d\n", stretchDepth, check)
|
||||
|
||||
longLivedTree := bottomUpTree(0, maxDepth)
|
||||
|
||||
for depth := minDepth; depth <= maxDepth; depth += 2 {
|
||||
iterations := 1 << uint(maxDepth-depth+minDepth)
|
||||
check = 0
|
||||
|
||||
for i := 1; i <= iterations; i++ {
|
||||
check += bottomUpTree(i, depth).itemCheck()
|
||||
check += bottomUpTree(-i, depth).itemCheck()
|
||||
}
|
||||
fmt.Printf("%d\t trees of depth %d\t check: %d\n", iterations*2, depth, check)
|
||||
}
|
||||
fmt.Printf("long lived tree of depth %d\t check: %d\n", maxDepth, longLivedTree.itemCheck())
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
stretch tree of depth 16 check: -1
|
||||
65536 trees of depth 4 check: -65536
|
||||
16384 trees of depth 6 check: -16384
|
||||
4096 trees of depth 8 check: -4096
|
||||
1024 trees of depth 10 check: -1024
|
||||
256 trees of depth 12 check: -256
|
||||
64 trees of depth 14 check: -64
|
||||
long lived tree of depth 15 check: -1
|
|
@ -0,0 +1,330 @@
|
|||
/*
|
||||
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 "The Computer Language Benchmarks Game" nor the
|
||||
name of "The Computer Language Shootout Benchmarks" 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.
|
||||
*/
|
||||
|
||||
/* The Computer Language Benchmarks Game
|
||||
http://shootout.alioth.debian.org/
|
||||
|
||||
contributed by Michael Barker
|
||||
based on a Java contribution by Luzius Meisser
|
||||
|
||||
convert to C by dualamd
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <pthread.h>
|
||||
|
||||
|
||||
enum Colour
|
||||
{
|
||||
blue = 0,
|
||||
red = 1,
|
||||
yellow = 2,
|
||||
Invalid = 3
|
||||
};
|
||||
|
||||
const char* ColourName[] = {"blue", "red", "yellow"};
|
||||
const int STACK_SIZE = 32*1024;
|
||||
|
||||
typedef unsigned int BOOL;
|
||||
const BOOL TRUE = 1;
|
||||
const BOOL FALSE = 0;
|
||||
|
||||
int CreatureID = 0;
|
||||
|
||||
|
||||
enum Colour doCompliment(enum Colour c1, enum Colour c2)
|
||||
{
|
||||
switch (c1)
|
||||
{
|
||||
case blue:
|
||||
switch (c2)
|
||||
{
|
||||
case blue:
|
||||
return blue;
|
||||
case red:
|
||||
return yellow;
|
||||
case yellow:
|
||||
return red;
|
||||
default:
|
||||
goto errlb;
|
||||
}
|
||||
case red:
|
||||
switch (c2)
|
||||
{
|
||||
case blue:
|
||||
return yellow;
|
||||
case red:
|
||||
return red;
|
||||
case yellow:
|
||||
return blue;
|
||||
default:
|
||||
goto errlb;
|
||||
}
|
||||
case yellow:
|
||||
switch (c2)
|
||||
{
|
||||
case blue:
|
||||
return red;
|
||||
case red:
|
||||
return blue;
|
||||
case yellow:
|
||||
return yellow;
|
||||
default:
|
||||
goto errlb;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
errlb:
|
||||
printf("Invalid colour\n");
|
||||
exit( 1 );
|
||||
}
|
||||
|
||||
/* convert integer to number string: 1234 -> "one two three four" */
|
||||
char* formatNumber(int n, char* outbuf)
|
||||
{
|
||||
int ochar = 0, ichar = 0;
|
||||
int i;
|
||||
char tmp[64];
|
||||
|
||||
const char* NUMBERS[] =
|
||||
{
|
||||
"zero", "one", "two", "three", "four", "five",
|
||||
"six", "seven", "eight", "nine"
|
||||
};
|
||||
|
||||
ichar = sprintf(tmp, "%d", n);
|
||||
|
||||
for (i = 0; i < ichar; i++)
|
||||
ochar += sprintf( outbuf + ochar, " %s", NUMBERS[ tmp[i] - '0' ] );
|
||||
|
||||
return outbuf;
|
||||
}
|
||||
|
||||
|
||||
struct MeetingPlace
|
||||
{
|
||||
pthread_mutex_t mutex;
|
||||
int meetingsLeft;
|
||||
struct Creature* firstCreature;
|
||||
};
|
||||
|
||||
struct Creature
|
||||
{
|
||||
pthread_t ht;
|
||||
pthread_attr_t stack_att;
|
||||
|
||||
struct MeetingPlace* place;
|
||||
int count;
|
||||
int sameCount;
|
||||
|
||||
enum Colour colour;
|
||||
int id;
|
||||
|
||||
BOOL two_met;
|
||||
BOOL sameid;
|
||||
};
|
||||
|
||||
|
||||
void MeetingPlace_Init(struct MeetingPlace* m, int meetings )
|
||||
{
|
||||
pthread_mutex_init( &m->mutex, 0 );
|
||||
m->meetingsLeft = meetings;
|
||||
m->firstCreature = 0;
|
||||
}
|
||||
|
||||
|
||||
BOOL Meet( struct Creature* cr)
|
||||
{
|
||||
BOOL retval = TRUE;
|
||||
|
||||
struct MeetingPlace* mp = cr->place;
|
||||
pthread_mutex_lock( &(mp->mutex) );
|
||||
|
||||
if ( mp->meetingsLeft > 0 )
|
||||
{
|
||||
if ( mp->firstCreature == 0 )
|
||||
{
|
||||
cr->two_met = FALSE;
|
||||
mp->firstCreature = cr;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct Creature* first;
|
||||
enum Colour newColour;
|
||||
|
||||
first = mp->firstCreature;
|
||||
newColour = doCompliment( cr->colour, first->colour );
|
||||
|
||||
cr->sameid = cr->id == first->id;
|
||||
cr->colour = newColour;
|
||||
cr->two_met = TRUE;
|
||||
|
||||
first->sameid = cr->sameid;
|
||||
first->colour = newColour;
|
||||
first->two_met = TRUE;
|
||||
|
||||
mp->firstCreature = 0;
|
||||
mp->meetingsLeft--;
|
||||
}
|
||||
}
|
||||
else
|
||||
retval = FALSE;
|
||||
|
||||
pthread_mutex_unlock( &(mp->mutex) );
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
void* CreatureThreadRun(void* param)
|
||||
{
|
||||
struct Creature* cr = (struct Creature*)param;
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
if ( Meet(cr) )
|
||||
{
|
||||
while (cr->two_met == FALSE)
|
||||
sched_yield();
|
||||
|
||||
if (cr->sameid)
|
||||
cr->sameCount++;
|
||||
cr->count++;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Creature_Init( struct Creature *cr, struct MeetingPlace* place, enum Colour colour )
|
||||
{
|
||||
cr->place = place;
|
||||
cr->count = cr->sameCount = 0;
|
||||
|
||||
cr->id = ++CreatureID;
|
||||
cr->colour = colour;
|
||||
cr->two_met = FALSE;
|
||||
|
||||
pthread_attr_init( &cr->stack_att );
|
||||
pthread_attr_setstacksize( &cr->stack_att, STACK_SIZE );
|
||||
pthread_create( &cr->ht, &cr->stack_att, &CreatureThreadRun, (void*)(cr) );
|
||||
}
|
||||
|
||||
/* format meeting times of each creature to string */
|
||||
char* Creature_getResult(struct Creature* cr, char* str)
|
||||
{
|
||||
char numstr[256];
|
||||
formatNumber(cr->sameCount, numstr);
|
||||
|
||||
sprintf( str, "%u%s", cr->count, numstr );
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
void runGame( int n_meeting, int ncolor, const enum Colour* colours )
|
||||
{
|
||||
int i;
|
||||
int total = 0;
|
||||
char str[256];
|
||||
|
||||
struct MeetingPlace place;
|
||||
struct Creature *creatures = (struct Creature*) calloc( ncolor, sizeof(struct Creature) );
|
||||
|
||||
MeetingPlace_Init( &place, n_meeting );
|
||||
|
||||
/* print initial color of each creature */
|
||||
for (i = 0; i < ncolor; i++)
|
||||
{
|
||||
printf( "%s ", ColourName[ colours[i] ] );
|
||||
Creature_Init( &(creatures[i]), &place, colours[i] );
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
/* wait for them to meet */
|
||||
for (i = 0; i < ncolor; i++)
|
||||
pthread_join( creatures[i].ht, 0 );
|
||||
|
||||
/* print meeting times of each creature */
|
||||
for (i = 0; i < ncolor; i++)
|
||||
{
|
||||
printf( "%s\n", Creature_getResult(&(creatures[i]), str) );
|
||||
total += creatures[i].count;
|
||||
}
|
||||
|
||||
/* print total meeting times, should equal n_meeting */
|
||||
printf( "%s\n\n", formatNumber(total, str) );
|
||||
|
||||
/* cleaup & quit */
|
||||
pthread_mutex_destroy( &place.mutex );
|
||||
free( creatures );
|
||||
}
|
||||
|
||||
|
||||
void printColours( enum Colour c1, enum Colour c2 )
|
||||
{
|
||||
printf( "%s + %s -> %s\n",
|
||||
ColourName[c1],
|
||||
ColourName[c2],
|
||||
ColourName[doCompliment(c1, c2)] );
|
||||
}
|
||||
|
||||
void printColoursTable(void)
|
||||
{
|
||||
printColours(blue, blue);
|
||||
printColours(blue, red);
|
||||
printColours(blue, yellow);
|
||||
printColours(red, blue);
|
||||
printColours(red, red);
|
||||
printColours(red, yellow);
|
||||
printColours(yellow, blue);
|
||||
printColours(yellow, red);
|
||||
printColours(yellow, yellow);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int n = (argc == 2) ? atoi(argv[1]) : 600;
|
||||
|
||||
printColoursTable();
|
||||
printf("\n");
|
||||
|
||||
const enum Colour r1[] = { blue, red, yellow };
|
||||
const enum Colour r2[] = { blue, red, yellow,
|
||||
red, yellow, blue,
|
||||
red, yellow, red, blue };
|
||||
|
||||
runGame( n, sizeof(r1) / sizeof(r1[0]), r1 );
|
||||
runGame( n, sizeof(r2) / sizeof(r2[0]), r2 );
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
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 "The Computer Language Benchmarks Game" nor the
|
||||
name of "The Computer Language Shootout Benchmarks" 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.
|
||||
*/
|
||||
|
||||
/* The Computer Language Benchmarks Game
|
||||
* http://shootout.alioth.debian.org/
|
||||
*
|
||||
* contributed by The Go Authors.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const (
|
||||
blue = iota
|
||||
red
|
||||
yellow
|
||||
ncol
|
||||
)
|
||||
|
||||
var complement = [...]int{
|
||||
red | red<<2: red,
|
||||
red | yellow<<2: blue,
|
||||
red | blue<<2: yellow,
|
||||
yellow | red<<2: blue,
|
||||
yellow | yellow<<2: yellow,
|
||||
yellow | blue<<2: red,
|
||||
blue | red<<2: yellow,
|
||||
blue | yellow<<2: red,
|
||||
blue | blue<<2: blue,
|
||||
}
|
||||
|
||||
var colname = [...]string{
|
||||
blue: "blue",
|
||||
red: "red",
|
||||
yellow: "yellow",
|
||||
}
|
||||
|
||||
// information about the current state of a creature.
|
||||
type info struct {
|
||||
colour int // creature's current colour.
|
||||
name int // creature's name.
|
||||
}
|
||||
|
||||
// exclusive access data-structure kept inside meetingplace.
|
||||
// if mate is nil, it indicates there's no creature currently waiting;
|
||||
// otherwise the creature's info is stored in info, and
|
||||
// it is waiting to receive its mate's information on the mate channel.
|
||||
type rendez struct {
|
||||
n int // current number of encounters.
|
||||
mate chan<- info // creature waiting when non-nil.
|
||||
info info // info about creature waiting.
|
||||
}
|
||||
|
||||
// result sent by each creature at the end of processing.
|
||||
type result struct {
|
||||
met int
|
||||
same int
|
||||
}
|
||||
|
||||
var n = 600
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
if flag.NArg() > 0 {
|
||||
n, _ = strconv.Atoi(flag.Arg(0))
|
||||
}
|
||||
|
||||
for c0 := 0; c0 < ncol; c0++ {
|
||||
for c1 := 0; c1 < ncol; c1++ {
|
||||
fmt.Printf("%s + %s -> %s\n", colname[c0], colname[c1], colname[complement[c0|c1<<2]])
|
||||
}
|
||||
}
|
||||
fmt.Print("\n")
|
||||
|
||||
pallmall([]int{blue, red, yellow})
|
||||
pallmall([]int{blue, red, yellow, red, yellow, blue, red, yellow, red, blue})
|
||||
}
|
||||
|
||||
func pallmall(cols []int) {
|
||||
|
||||
// invariant: meetingplace always contains a value unless a creature
|
||||
// is currently dealing with it (whereupon it must put it back).
|
||||
meetingplace := make(chan rendez, 1)
|
||||
meetingplace <- rendez{n: 0}
|
||||
|
||||
ended := make(chan result)
|
||||
msg := ""
|
||||
for i, col := range cols {
|
||||
go creature(info{col, i}, meetingplace, ended)
|
||||
msg += " " + colname[col]
|
||||
}
|
||||
fmt.Println(msg)
|
||||
tot := 0
|
||||
// wait for all results
|
||||
for _ = range cols {
|
||||
result := <-ended
|
||||
tot += result.met
|
||||
fmt.Printf("%v%v\n", result.met, spell(result.same, true))
|
||||
}
|
||||
fmt.Printf("%v\n\n", spell(tot, true))
|
||||
}
|
||||
|
||||
// in this function, variables ending in 0 refer to the local creature,
|
||||
// variables ending in 1 to the creature we've met.
|
||||
func creature(info0 info, meetingplace chan rendez, ended chan result) {
|
||||
c0 := make(chan info)
|
||||
met := 0
|
||||
same := 0
|
||||
for {
|
||||
var othername int
|
||||
// get access to rendez data and decide what to do.
|
||||
switch r := <-meetingplace; {
|
||||
case r.n >= n:
|
||||
// if no more meetings left, then send our result data and exit.
|
||||
meetingplace <- rendez{n: r.n}
|
||||
ended <- result{met, same}
|
||||
return
|
||||
case r.mate == nil:
|
||||
// no creature waiting; wait for someone to meet us,
|
||||
// get their info and send our info in reply.
|
||||
meetingplace <- rendez{n: r.n, info: info0, mate: c0}
|
||||
info1 := <-c0
|
||||
othername = info1.name
|
||||
info0.colour = complement[info0.colour|info1.colour<<2]
|
||||
default:
|
||||
// another creature is waiting for us with its info;
|
||||
// increment meeting count,
|
||||
// send them our info in reply.
|
||||
r.n++
|
||||
meetingplace <- rendez{n: r.n, mate: nil}
|
||||
r.mate <- info0
|
||||
othername = r.info.name
|
||||
info0.colour = complement[info0.colour|r.info.colour<<2]
|
||||
}
|
||||
if othername == info0.name {
|
||||
same++
|
||||
}
|
||||
met++
|
||||
}
|
||||
}
|
||||
|
||||
var digits = [...]string{"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"}
|
||||
|
||||
func spell(n int, required bool) string {
|
||||
if n == 0 && !required {
|
||||
return ""
|
||||
}
|
||||
return spell(n/10, false) + " " + digits[n%10]
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
blue + blue -> blue
|
||||
blue + red -> yellow
|
||||
blue + yellow -> red
|
||||
red + blue -> yellow
|
||||
red + red -> red
|
||||
red + yellow -> blue
|
||||
yellow + blue -> red
|
||||
yellow + red -> blue
|
||||
yellow + yellow -> yellow
|
||||
|
||||
blue red yellow
|
||||
400 zero
|
||||
400 zero
|
||||
400 zero
|
||||
one two zero zero
|
||||
|
||||
blue red yellow red yellow blue red yellow red blue
|
||||
120 zero
|
||||
120 zero
|
||||
120 zero
|
||||
120 zero
|
||||
120 zero
|
||||
120 zero
|
||||
120 zero
|
||||
120 zero
|
||||
120 zero
|
||||
120 zero
|
||||
one two zero zero
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
#!/bin/sh
|
||||
|
||||
OS=568
|
||||
rm -f [$OS].out *.[$OS]
|
|
@ -0,0 +1,224 @@
|
|||
/*
|
||||
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 "The Computer Language Benchmarks Game" nor the
|
||||
name of "The Computer Language Shootout Benchmarks" 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The Computer Language Benchmarks Game
|
||||
* http://shootout.alioth.debian.org/
|
||||
*
|
||||
* contributed by The Go Authors.
|
||||
* Based on fannkuch.scala by Rex Kerr
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
var n = flag.Int("n", 7, "count")
|
||||
var nCPU = flag.Int("ncpu", 2, "number of cpus")
|
||||
|
||||
type Job struct {
|
||||
start []int
|
||||
n int
|
||||
}
|
||||
|
||||
type Found struct {
|
||||
who *Kucher
|
||||
k int
|
||||
}
|
||||
|
||||
type Kucher struct {
|
||||
perm []int
|
||||
temp []int
|
||||
flip []int
|
||||
in chan Job
|
||||
}
|
||||
|
||||
func NewKucher(length int) *Kucher {
|
||||
return &Kucher{
|
||||
perm: make([]int, length),
|
||||
temp: make([]int, length),
|
||||
flip: make([]int, length),
|
||||
in: make(chan Job),
|
||||
}
|
||||
}
|
||||
|
||||
func (k *Kucher) permute(n int) bool {
|
||||
i := 0
|
||||
for ; i < n-1 && k.flip[i] == 0; i++ {
|
||||
t := k.perm[0]
|
||||
j := 0
|
||||
for ; j <= i; j++ {
|
||||
k.perm[j] = k.perm[j+1]
|
||||
}
|
||||
k.perm[j] = t
|
||||
}
|
||||
k.flip[i]--
|
||||
for i > 0 {
|
||||
i--
|
||||
k.flip[i] = i
|
||||
}
|
||||
return k.flip[n-1] >= 0
|
||||
}
|
||||
|
||||
func (k *Kucher) count() int {
|
||||
K := 0
|
||||
copy(k.temp, k.perm)
|
||||
for k.temp[0] != 0 {
|
||||
m := k.temp[0]
|
||||
for i := 0; i < m; i++ {
|
||||
k.temp[i], k.temp[m] = k.temp[m], k.temp[i]
|
||||
m--
|
||||
}
|
||||
K++
|
||||
}
|
||||
return K
|
||||
}
|
||||
|
||||
func (k *Kucher) Run(foreman chan<- Found) {
|
||||
for job := range k.in {
|
||||
verbose := 30
|
||||
copy(k.perm, job.start)
|
||||
for i, v := range k.perm {
|
||||
if v != i {
|
||||
verbose = 0
|
||||
}
|
||||
k.flip[i] = i
|
||||
}
|
||||
K := 0
|
||||
for {
|
||||
if verbose > 0 {
|
||||
for _, p := range k.perm {
|
||||
fmt.Print(p + 1)
|
||||
}
|
||||
fmt.Println()
|
||||
verbose--
|
||||
}
|
||||
count := k.count()
|
||||
if count > K {
|
||||
K = count
|
||||
}
|
||||
if !k.permute(job.n) {
|
||||
break
|
||||
}
|
||||
}
|
||||
foreman <- Found{k, K}
|
||||
}
|
||||
}
|
||||
|
||||
type Fanner struct {
|
||||
jobind int
|
||||
jobsdone int
|
||||
k int
|
||||
jobs []Job
|
||||
workers []*Kucher
|
||||
in chan Found
|
||||
result chan int
|
||||
}
|
||||
|
||||
func NewFanner(jobs []Job, workers []*Kucher) *Fanner {
|
||||
return &Fanner{
|
||||
jobs: jobs, workers: workers,
|
||||
in: make(chan Found),
|
||||
result: make(chan int),
|
||||
}
|
||||
}
|
||||
|
||||
func (f *Fanner) Run(N int) {
|
||||
for msg := range f.in {
|
||||
if msg.k > f.k {
|
||||
f.k = msg.k
|
||||
}
|
||||
if msg.k >= 0 {
|
||||
f.jobsdone++
|
||||
}
|
||||
if f.jobind < len(f.jobs) {
|
||||
msg.who.in <- f.jobs[f.jobind]
|
||||
f.jobind++
|
||||
} else if f.jobsdone == len(f.jobs) {
|
||||
f.result <- f.k
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func swapped(a []int, i, j int) []int {
|
||||
b := make([]int, len(a))
|
||||
copy(b, a)
|
||||
b[i], b[j] = a[j], a[i]
|
||||
return b
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
runtime.GOMAXPROCS(*nCPU)
|
||||
N := *n
|
||||
base := make([]int, N)
|
||||
for i := range base {
|
||||
base[i] = i
|
||||
}
|
||||
|
||||
njobs := 1
|
||||
if N > 8 {
|
||||
njobs += (N*(N-1))/2 - 28 // njobs = 1 + sum(8..N-1) = 1 + sum(1..N-1) - sum(1..7)
|
||||
}
|
||||
jobs := make([]Job, njobs)
|
||||
jobsind := 0
|
||||
|
||||
firstN := N
|
||||
if firstN > 8 {
|
||||
firstN = 8
|
||||
}
|
||||
jobs[jobsind] = Job{base, firstN}
|
||||
jobsind++
|
||||
for i := N - 1; i >= 8; i-- {
|
||||
for j := 0; j < i; j++ {
|
||||
jobs[jobsind] = Job{swapped(base, i, j), i}
|
||||
jobsind++
|
||||
}
|
||||
}
|
||||
|
||||
nworkers := *nCPU
|
||||
if njobs < nworkers {
|
||||
nworkers = njobs
|
||||
}
|
||||
workers := make([]*Kucher, nworkers)
|
||||
foreman := NewFanner(jobs, workers)
|
||||
go foreman.Run(N)
|
||||
for i := range workers {
|
||||
k := NewKucher(N)
|
||||
workers[i] = k
|
||||
go k.Run(foreman.in)
|
||||
foreman.in <- Found{k, -1}
|
||||
}
|
||||
fmt.Printf("Pfannkuchen(%d) = %d\n", N, <-foreman.result)
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue