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:
Ian Lance Taylor 2010-12-03 04:34:57 +00:00
parent 1aa6700378
commit 7a9389330e
1565 changed files with 351565 additions and 12 deletions

View File

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

View File

@ -2272,6 +2272,10 @@ Driver
static-libstdc++
Driver
static-libgo
Driver
; Documented for Go, but always accepted by driver.
symbolic
Driver

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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",

267
gcc/go/Make-lang.in Normal file
View File

@ -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)

3
gcc/go/README.gcc Normal file
View File

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

37
gcc/go/config-lang.in Normal file
View File

@ -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"

348
gcc/go/gccgo.texi Normal file
View File

@ -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(&amp;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

66
gcc/go/go-c.h Normal file
View File

@ -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) */

404
gcc/go/go-lang.c Normal file
View File

@ -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"

153
gcc/go/go-system.h Normal file
View File

@ -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)

42
gcc/go/gofrontend/LICENSE Normal file
View File

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

57
gcc/go/gofrontend/README Normal file
View File

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

View File

@ -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;
}

View File

@ -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)

441
gcc/go/gofrontend/export.cc Normal file
View File

@ -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);
}

191
gcc/go/gofrontend/export.h Normal file
View File

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

View File

@ -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;
}

View File

@ -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)

153
gcc/go/gofrontend/go.cc Normal file
View File

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

4274
gcc/go/gofrontend/gogo.cc Normal file

File diff suppressed because it is too large Load Diff

2484
gcc/go/gofrontend/gogo.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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;
}

892
gcc/go/gofrontend/import.cc Normal file
View File

@ -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, &parameters, &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();
}
}

351
gcc/go/gofrontend/import.h Normal file
View File

@ -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)

2287
gcc/go/gofrontend/lex.cc Normal file

File diff suppressed because it is too large Load Diff

446
gcc/go/gofrontend/lex.h Normal file
View File

@ -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)

View File

@ -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)

4730
gcc/go/gofrontend/parse.cc Normal file

File diff suppressed because it is too large Load Diff

307
gcc/go/gofrontend/parse.h Normal file
View File

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

8078
gcc/go/gofrontend/types.cc Normal file

File diff suppressed because it is too large Load Diff

2730
gcc/go/gofrontend/types.h Normal file

File diff suppressed because it is too large Load Diff

134
gcc/go/gofrontend/unsafe.cc Normal file
View File

@ -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;
}

327
gcc/go/gospec.c Normal file
View File

@ -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. */

25
gcc/go/lang-specs.h Normal file
View File

@ -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},

56
gcc/go/lang.opt Normal file
View File

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

View File

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

View File

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

View File

@ -0,0 +1,7 @@
// { dg-do compile }
package main
func main() {
var ret; // { dg-error "expected type" }
}

View File

@ -0,0 +1,7 @@
// { dg-do compile }
package main
func main() {
goto lab; // { dg-error "undefined label" }
}

View File

@ -0,0 +1,7 @@
// { dg-do compile }
package main
func main() {
sys.Exit(i) // { dg-error "undefined" }
}

View File

@ -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) }
}

View File

@ -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);
}
}

View File

@ -0,0 +1,7 @@
package main
func main() {
c := make(chan int, 1);
c <- 0;
if <-c != 0 { panic(0) }
}

View File

@ -0,0 +1,6 @@
package main
func main() {
const c = 2;
if c != 2 { panic(0) }
}

View File

@ -0,0 +1,7 @@
package main
const c = 3;
func main() {
if c != 3 { panic(0) }
}

View File

@ -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
}

View File

@ -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)
}
}

View File

@ -0,0 +1,9 @@
package main
func main() {
sum := 0;
for i := 0; i < 10; i++ {
sum += i;
}
if sum != 45 { panic(0) }
}

View File

@ -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()
}

View File

@ -0,0 +1,9 @@
package main
func subr() int {
return 0
}
func main() {
if subr() != 0 { panic(0) }
}

View File

@ -0,0 +1,9 @@
package main
func subr(p int) int {
return p
}
func main() {
if subr(0) != 0 { panic(0) }
}

View File

@ -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) }
}

View File

@ -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) }
}

View File

@ -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) }
}

View File

@ -0,0 +1,7 @@
package main
func main() {
goto lab;
panic(0);
lab:
}

View File

@ -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)
}
}

View File

@ -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) }
}

View File

@ -0,0 +1,4 @@
package main
func main() {
if func (i int) int { return i} (0) != 0 { panic(0) }
}

View File

@ -0,0 +1,7 @@
package main
func main() {
p := new(int);
*p = 0;
if *p != 0 { panic(0) }
}

View File

@ -0,0 +1,4 @@
package main
func main() {
}

View File

@ -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) }
}

View File

@ -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) }
}

View File

@ -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)
}
}

View File

@ -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);
}
}

View File

@ -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)
}
}

View File

@ -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) }
}

View File

@ -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) }
}

View File

@ -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);
}
}

View File

@ -0,0 +1,6 @@
package main
func main() {
var ret = 0;
if ret != 0 { panic(0) }
}

View File

@ -0,0 +1,6 @@
package main
func main() {
var ret int;
if ret != 0 { panic(0) }
}

View File

@ -0,0 +1,6 @@
package main
func main() {
ret := 0;
if ret != 0 { panic(0) }
}

View File

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

View File

@ -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")
}
}
}

View File

@ -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()
}

View File

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

View File

@ -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")
}
}

View File

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

View File

@ -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
}
}

View File

@ -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)
}

View File

@ -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())
}

View File

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

View File

@ -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() */

View File

@ -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())
}

View File

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

View File

@ -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;
}

View File

@ -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]
}

View File

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

View File

@ -0,0 +1,4 @@
#!/bin/sh
OS=568
rm -f [$OS].out *.[$OS]

View File

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