changeset 1:c53b6e3fe49a trunk

[svn r5] Initial commit. Most things are very rough.
author lindquist
date Sat, 01 Sep 2007 21:43:27 +0200
parents a9e71648e74d
children 1fb7ce03965b
files dmd/Doxyfile dmd/access.c dmd/aggregate.h dmd/array.c dmd/arraytypes.h dmd/artistic.txt dmd/attrib.c dmd/attrib.h dmd/cast.c dmd/class.c dmd/complex_t.h dmd/cond.c dmd/cond.h dmd/constfold.c dmd/dchar.c dmd/dchar.h dmd/declaration.c dmd/declaration.h dmd/delegatize.c dmd/doc.c dmd/doc.h dmd/dsymbol.c dmd/dsymbol.h dmd/dump.c dmd/entity.c dmd/enum.c dmd/enum.h dmd/expression.c dmd/expression.h dmd/func.c dmd/gnuc.c dmd/gnuc.h dmd/gpl.txt dmd/hdrgen.c dmd/hdrgen.h dmd/html.c dmd/html.h dmd/id.c dmd/id.h dmd/identifier.c dmd/identifier.h dmd/idgen.c dmd/impcnvgen.c dmd/impcnvtab.c dmd/import.c dmd/import.h dmd/inifile.c dmd/init.c dmd/init.h dmd/inline.c dmd/interpret.c dmd/lexer.c dmd/lexer.h dmd/link.c dmd/lstring.c dmd/lstring.h dmd/macro.c dmd/macro.h dmd/mangle.c dmd/mars.c dmd/mars.h dmd/mem.c dmd/mem.h dmd/module.c dmd/module.h dmd/mtype.c dmd/mtype.h dmd/opover.c dmd/optimize.c dmd/parse.c dmd/parse.h dmd/port.h dmd/readme.txt dmd/root.c dmd/root.h dmd/scope.c dmd/scope.h dmd/statement.c dmd/statement.h dmd/staticassert.c dmd/staticassert.h dmd/stringtable.c dmd/stringtable.h dmd/struct.c dmd/template.c dmd/template.h dmd/total.h dmd/unialpha.c dmd/utf.c dmd/utf.h dmd/version.c dmd/version.h gen/elem.c gen/elem.h gen/enums.h gen/irstate.c gen/irstate.h gen/logger.c gen/logger.h gen/runtime.c gen/runtime.h gen/symbol.h gen/tocsym.c gen/todt.c gen/toir.c gen/tollvm.c gen/tollvm.h gen/toobj.c gen/typinf.c lphobos/build.sh lphobos/clean.sh lphobos/crc32.d lphobos/dsss.conf lphobos/gcstats.d lphobos/internal/arrays.d lphobos/internal/contract.d lphobos/internal/moduleinit.d lphobos/internal/moduleinit_backend.ll lphobos/internal/objectimpl.d lphobos/llvm/intrinsic.d lphobos/object.d lphobos/std/c/fenv.d lphobos/std/c/linux/linux.d lphobos/std/c/linux/linuxextern.d lphobos/std/c/linux/pthread.d lphobos/std/c/linux/socket.d lphobos/std/c/locale.d lphobos/std/c/math.d lphobos/std/c/process.d lphobos/std/c/stdarg.d lphobos/std/c/stddef.d lphobos/std/c/stdio.d lphobos/std/c/stdlib.d lphobos/std/c/string.d lphobos/std/c/time.d lphobos/std/intrinsic.d lphobos/std/stdint.d lphobos/std/typeinfo/ti_Aint.d lphobos/std/typeinfo/ti_byte.d lphobos/std/typeinfo/ti_char.d lphobos/std/typeinfo/ti_int.d lphobos/std/typeinfo/ti_ptr.d lphobos/std/typeinfo/ti_short.d lphobos/std/typeinfo/ti_ubyte.d lphobos/std/typeinfo/ti_uint.d lphobos/std/typeinfo/ti_ushort.d lphobos/std/typeinfounsupported/ti_AC.d lphobos/std/typeinfounsupported/ti_Acdouble.d lphobos/std/typeinfounsupported/ti_Acfloat.d lphobos/std/typeinfounsupported/ti_Acreal.d lphobos/std/typeinfounsupported/ti_Adouble.d lphobos/std/typeinfounsupported/ti_Afloat.d lphobos/std/typeinfounsupported/ti_Ag.d lphobos/std/typeinfounsupported/ti_Aint.d lphobos/std/typeinfounsupported/ti_Along.d lphobos/std/typeinfounsupported/ti_Areal.d lphobos/std/typeinfounsupported/ti_Ashort.d lphobos/std/typeinfounsupported/ti_C.d lphobos/std/typeinfounsupported/ti_byte.d lphobos/std/typeinfounsupported/ti_cdouble.d lphobos/std/typeinfounsupported/ti_cfloat.d lphobos/std/typeinfounsupported/ti_char.d lphobos/std/typeinfounsupported/ti_creal.d lphobos/std/typeinfounsupported/ti_dchar.d lphobos/std/typeinfounsupported/ti_delegate.d lphobos/std/typeinfounsupported/ti_double.d lphobos/std/typeinfounsupported/ti_float.d lphobos/std/typeinfounsupported/ti_idouble.d lphobos/std/typeinfounsupported/ti_ifloat.d lphobos/std/typeinfounsupported/ti_int.d lphobos/std/typeinfounsupported/ti_ireal.d lphobos/std/typeinfounsupported/ti_long.d lphobos/std/typeinfounsupported/ti_ptr.d lphobos/std/typeinfounsupported/ti_real.d lphobos/std/typeinfounsupported/ti_short.d lphobos/std/typeinfounsupported/ti_ubyte.d lphobos/std/typeinfounsupported/ti_uint.d lphobos/std/typeinfounsupported/ti_ulong.d lphobos/std/typeinfounsupported/ti_ushort.d lphobos/std/typeinfounsupported/ti_void.d lphobos/std/typeinfounsupported/ti_wchar.d premake.lua test/a.d test/alignment.d test/arrayinit.d test/arrays.d test/arrays2.d test/assign.d test/b.d test/bitops.d test/c.d test/classes.d test/classes2.d test/classes3.d test/classes4.d test/comma.d test/cond.d test/condexp.d test/cyclic.d test/d.d test/dgs.d test/dotproduct.d test/e.d test/f.d test/floatcmp.d test/forwdecl.d test/funcptr.d test/funcs.d test/imports_1of2.d test/imports_2of2.d test/intrinsics.d test/pointers.d test/pt.d test/ptrarith.d test/sieve.d test/slices.d test/static_ctor.d test/staticarrays.d test/structinit.d test/structinit2.d test/structs.d test/structs2.d test/terms.d test/typeinfo.d test/v2d.d test/virtcall.d tester.sh
diffstat 226 files changed, 84269 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/Doxyfile	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,1257 @@
+# Doxyfile 1.5.2
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file that
+# follow. The default is UTF-8 which is also the encoding used for all text before
+# the first occurrence of this tag. Doxygen uses libiconv (or the iconv built into
+# libc) for the transcoding. See http://www.gnu.org/software/libiconv for the list of
+# possible encodings.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = DMDFE
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER         = 1.020
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = docs
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian,
+# Italian, Japanese, Japanese-en (Japanese with English messages), Korean,
+# Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian,
+# Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH        =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like the Qt-style comments (thus requiring an
+# explicit @brief command for a brief description.
+
+JAVADOC_AUTOBRIEF      = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member
+# documentation.
+
+DETAILS_AT_TOP         = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for Java.
+# For instance, namespaces will be presented as packages, qualified scopes
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to
+# include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT        = NO
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES       = NO
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from the
+# version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER    =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT                  =
+
+# This tag can be used to specify the character encoding of the source files that
+# doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default
+# input encoding. Doxygen uses libiconv (or the iconv built into libc) for the transcoding.
+# See http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py
+
+FILE_PATTERNS          =
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the output.
+# The symbol name can be a fully qualified name, a word, or if the wildcard * is used,
+# a substring. Examples: ANamespace, AClass, AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS       =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.  If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis.  Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match.  The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default)
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default)
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.  Otherwise they will link to the documentstion.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET        =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE               =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX          = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
+# probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW      = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX         = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA             =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD                =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.  This is useful
+# if you want to understand what is going on.  On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED             =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+#   TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#   TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see http://www.mcternan.me.uk/mscgen/) to
+# produce the chart and insert it in the documentation. The MSCGEN_PATH tag allows you to
+# specify the directory where the mscgen tool resides. If left empty the tool is assumed to
+# be found in the default search path.
+
+MSCGEN_PATH            =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = NO
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK               = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will
+# generate a call dependency graph for every global function or class method.
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then doxygen will
+# generate a caller dependency graph for every global function or class method.
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS           =
+
+# The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen will always
+# show the root nodes and its direct children regardless of this setting.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, which results in a white background.
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP            = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE           = NO
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/access.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,423 @@
+
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "root.h"
+#include "mem.h"
+
+#include "enum.h"
+#include "aggregate.h"
+#include "init.h"
+#include "attrib.h"
+#include "scope.h"
+#include "id.h"
+#include "mtype.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "expression.h"
+#include "module.h"
+
+#define LOG 0
+
+/* Code to do access checks
+ */
+
+int hasPackageAccess(Scope *sc, Dsymbol *s);
+
+/****************************************
+ * Return PROT access for Dsymbol smember in this declaration.
+ */
+
+enum PROT AggregateDeclaration::getAccess(Dsymbol *smember)
+{
+    return PROTpublic;
+}
+
+enum PROT StructDeclaration::getAccess(Dsymbol *smember)
+{
+    enum PROT access_ret = PROTnone;
+
+#if LOG
+    printf("+StructDeclaration::getAccess(this = '%s', smember = '%s')\n",
+	toChars(), smember->toChars());
+#endif
+    if (smember->toParent() == this)
+    {
+	access_ret = smember->prot();
+    }
+    else if (smember->isDeclaration()->isStatic())
+    {
+	access_ret = smember->prot();
+    }
+    return access_ret;
+}
+
+enum PROT ClassDeclaration::getAccess(Dsymbol *smember)
+{
+    enum PROT access_ret = PROTnone;
+
+#if LOG
+    printf("+ClassDeclaration::getAccess(this = '%s', smember = '%s')\n",
+	toChars(), smember->toChars());
+#endif
+    if (smember->toParent() == this)
+    {
+	access_ret = smember->prot();
+    }
+    else
+    {
+	enum PROT access;
+	int i;
+
+	if (smember->isDeclaration()->isStatic())
+	{
+	    access_ret = smember->prot();
+	}
+
+	for (i = 0; i < baseclasses.dim; i++)
+	{   BaseClass *b = (BaseClass *)baseclasses.data[i];
+
+	    access = b->base->getAccess(smember);
+	    switch (access)
+	    {
+		case PROTnone:
+		    break;
+
+		case PROTprivate:
+		    access = PROTnone;	// private members of base class not accessible
+		    break;
+
+		case PROTpackage:
+		case PROTprotected:
+		case PROTpublic:
+		case PROTexport:
+		    // If access is to be tightened
+		    if (b->protection < access)
+			access = b->protection;
+
+		    // Pick path with loosest access
+		    if (access > access_ret)
+			access_ret = access;
+		    break;
+
+		default:
+		    assert(0);
+	    }
+	}
+    }
+#if LOG
+    printf("-ClassDeclaration::getAccess(this = '%s', smember = '%s') = %d\n",
+	toChars(), smember->toChars(), access_ret);
+#endif
+    return access_ret;
+}
+
+/********************************************************
+ * Helper function for ClassDeclaration::accessCheck()
+ * Returns:
+ *	0	no access
+ * 	1	access
+ */
+
+static int accessCheckX(
+	Dsymbol *smember,
+	Dsymbol *sfunc,
+	AggregateDeclaration *dthis,
+	AggregateDeclaration *cdscope)
+{
+    assert(dthis);
+
+#if 0
+    printf("accessCheckX for %s.%s in function %s() in scope %s\n",
+	dthis->toChars(), smember->toChars(),
+	sfunc ? sfunc->toChars() : "NULL",
+	cdscope ? cdscope->toChars() : "NULL");
+#endif
+    if (dthis->hasPrivateAccess(sfunc) ||
+	dthis->isFriendOf(cdscope))
+    {
+	if (smember->toParent() == dthis)
+	    return 1;
+	else
+	{
+	    ClassDeclaration *cdthis = dthis->isClassDeclaration();
+	    if (cdthis)
+	    {
+		for (int i = 0; i < cdthis->baseclasses.dim; i++)
+		{   BaseClass *b = (BaseClass *)cdthis->baseclasses.data[i];
+		    enum PROT access;
+
+		    access = b->base->getAccess(smember);
+		    if (access >= PROTprotected ||
+			accessCheckX(smember, sfunc, b->base, cdscope)
+		       )
+			return 1;
+
+		}
+	    }
+	}
+    }
+    else
+    {
+	if (smember->toParent() != dthis)
+	{
+	    ClassDeclaration *cdthis = dthis->isClassDeclaration();
+	    if (cdthis)
+	    {
+		for (int i = 0; i < cdthis->baseclasses.dim; i++)
+		{   BaseClass *b = (BaseClass *)cdthis->baseclasses.data[i];
+
+		    if (accessCheckX(smember, sfunc, b->base, cdscope))
+			return 1;
+		}
+	    }
+	}
+    }
+    return 0;
+}
+
+/*******************************
+ * Do access check for member of this class, this class being the
+ * type of the 'this' pointer used to access smember.
+ */
+
+void AggregateDeclaration::accessCheck(Loc loc, Scope *sc, Dsymbol *smember)
+{
+    int result;
+
+    FuncDeclaration *f = sc->func;
+    AggregateDeclaration *cdscope = sc->getStructClassScope();
+    enum PROT access;
+
+#if LOG
+    printf("AggregateDeclaration::accessCheck() for %s.%s in function %s() in scope %s\n",
+	toChars(), smember->toChars(),
+	f ? f->toChars() : NULL,
+	cdscope ? cdscope->toChars() : NULL);
+#endif
+
+    Dsymbol *smemberparent = smember->toParent();
+    if (!smemberparent || !smemberparent->isAggregateDeclaration())
+    {
+#if LOG
+	printf("not an aggregate member\n");
+#endif
+	return;				// then it is accessible
+    }
+
+    // BUG: should enable this check
+    //assert(smember->parent->isBaseOf(this, NULL));
+
+    if (smemberparent == this)
+    {	enum PROT access = smember->prot();
+
+	result = access >= PROTpublic ||
+		hasPrivateAccess(f) ||
+		isFriendOf(cdscope) ||
+		(access == PROTpackage && hasPackageAccess(sc, this));
+#if LOG
+	printf("result1 = %d\n", result);
+#endif
+    }
+    else if ((access = this->getAccess(smember)) >= PROTpublic)
+    {
+	result = 1;
+#if LOG
+	printf("result2 = %d\n", result);
+#endif
+    }
+    else if (access == PROTpackage && hasPackageAccess(sc, this))
+    {
+	result = 1;
+#if LOG
+	printf("result3 = %d\n", result);
+#endif
+    }
+    else
+    {
+	result = accessCheckX(smember, f, this, cdscope);
+#if LOG
+	printf("result4 = %d\n", result);
+#endif
+    }
+    if (!result)
+    {
+	error(loc, "member %s is not accessible", smember->toChars());
+    }
+}
+
+/****************************************
+ * Determine if this is the same or friend of cd.
+ */
+
+int AggregateDeclaration::isFriendOf(AggregateDeclaration *cd)
+{
+#if LOG
+    printf("AggregateDeclaration::isFriendOf(this = '%s', cd = '%s')\n", toChars(), cd ? cd->toChars() : "null");
+#endif
+    if (this == cd)
+	return 1;
+
+    // Friends if both are in the same module
+    //if (toParent() == cd->toParent())
+    if (cd && getModule() == cd->getModule())
+    {
+#if LOG
+	printf("\tin same module\n");
+#endif
+	return 1;
+    }
+
+#if LOG
+    printf("\tnot friend\n");
+#endif
+    return 0;
+}
+
+/****************************************
+ * Determine if scope sc has package level access to s.
+ */
+
+int hasPackageAccess(Scope *sc, Dsymbol *s)
+{
+#if LOG
+    printf("hasPackageAccess(s = '%s', sc = '%p')\n", s->toChars(), sc);
+#endif
+
+    for (; s; s = s->parent)
+    {
+	if (s->isPackage() && !s->isModule())
+	    break;
+    }
+#if LOG
+    if (s)
+	printf("\tthis is in package '%s'\n", s->toChars());
+#endif
+
+    if (s && s == sc->module->parent)
+    {
+#if LOG
+	printf("\ts is in same package as sc\n");
+#endif
+	return 1;
+    }
+
+
+#if LOG
+    printf("\tno package access\n");
+#endif
+    return 0;
+}
+
+/**********************************
+ * Determine if smember has access to private members of this declaration.
+ */
+
+int AggregateDeclaration::hasPrivateAccess(Dsymbol *smember)
+{
+    if (smember)
+    {	AggregateDeclaration *cd = NULL;
+	Dsymbol *smemberparent = smember->toParent();
+	if (smemberparent)
+	    cd = smemberparent->isAggregateDeclaration();
+
+#if LOG
+	printf("AggregateDeclaration::hasPrivateAccess(class %s, member %s)\n",
+		toChars(), smember->toChars());
+#endif
+
+	if (this == cd)		// smember is a member of this class
+	{
+#if LOG
+	    printf("\tyes 1\n");
+#endif
+	    return 1;		// so we get private access
+	}
+
+	// If both are members of the same module, grant access
+	while (1)
+	{   Dsymbol *sp = smember->toParent();
+	    if (sp->isFuncDeclaration() && smember->isFuncDeclaration())
+		smember = sp;
+	    else
+		break;
+	}
+	if (!cd && toParent() == smember->toParent())
+	{
+#if LOG
+	    printf("\tyes 2\n");
+#endif
+	    return 1;
+	}
+	if (!cd && getModule() == smember->getModule())
+	{
+#if LOG
+	    printf("\tyes 3\n");
+#endif
+	    return 1;
+	}
+    }
+#if LOG
+    printf("\tno\n");
+#endif
+    return 0;
+}
+
+/****************************************
+ * Check access to d for expression e.d
+ */
+
+void accessCheck(Loc loc, Scope *sc, Expression *e, Declaration *d)
+{
+#if LOG
+    if (e)
+    {	printf("accessCheck(%s . %s)\n", e->toChars(), d->toChars());
+	printf("\te->type = %s\n", e->type->toChars());
+    }
+    else
+    {
+	//printf("accessCheck(%s)\n", d->toChars());
+    }
+#endif
+    if (!e)
+    {
+	if (d->prot() == PROTprivate && d->getModule() != sc->module ||
+	    d->prot() == PROTpackage && !hasPackageAccess(sc, d))
+
+	    error(loc, "%s %s.%s is not accessible from %s",
+		d->kind(), d->getModule()->toChars(), d->toChars(), sc->module->toChars());
+    }
+    else if (e->type->ty == Tclass)
+    {   // Do access check
+	ClassDeclaration *cd;
+
+	cd = (ClassDeclaration *)(((TypeClass *)e->type)->sym);
+#if 1
+	if (e->op == TOKsuper)
+	{   ClassDeclaration *cd2;
+
+	    cd2 = sc->func->toParent()->isClassDeclaration();
+	    if (cd2)
+		cd = cd2;
+	}
+#endif
+	cd->accessCheck(loc, sc, d);
+    }
+    else if (e->type->ty == Tstruct)
+    {   // Do access check
+	StructDeclaration *cd;
+
+	cd = (StructDeclaration *)(((TypeStruct *)e->type)->sym);
+	cd->accessCheck(loc, sc, d);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/aggregate.h	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,256 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#ifndef DMD_AGGREGATE_H
+#define DMD_AGGREGATE_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+#include "root.h"
+#include "dsymbol.h"
+
+struct Identifier;
+struct Type;
+struct TypeFunction;
+struct Expression;
+struct FuncDeclaration;
+struct CtorDeclaration;
+struct DtorDeclaration;
+struct InvariantDeclaration;
+struct NewDeclaration;
+struct DeleteDeclaration;
+struct InterfaceDeclaration;
+struct ClassInfoDeclaration;
+struct VarDeclaration;
+struct dt_t;
+
+namespace llvm
+{
+    class Type;
+    class Value;
+    class Constant;
+}
+
+struct AggregateDeclaration : ScopeDsymbol
+{
+    Type *type;
+    unsigned storage_class;
+    enum PROT protection;
+    Type *handle;		// 'this' type
+    unsigned structsize;	// size of struct
+    unsigned alignsize;		// size of struct for alignment purposes
+    unsigned structalign;	// struct member alignment in effect
+    int hasUnions;		// set if aggregate has overlapping fields
+    Array fields;		// VarDeclaration fields
+    unsigned sizeok;		// set when structsize contains valid data
+				// 0: no size
+				// 1: size is correct
+				// 2: cannot determine size; fwd referenced
+    int isdeprecated;		// !=0 if deprecated
+    Scope *scope;		// !=NULL means context to use
+
+    // Special member functions
+    InvariantDeclaration *inv;		// invariant
+    NewDeclaration *aggNew;		// allocator
+    DeleteDeclaration *aggDelete;	// deallocator
+
+#ifdef IN_GCC
+    Array methods;              // flat list of all methods for debug information
+#endif
+
+    AggregateDeclaration(Loc loc, Identifier *id);
+    void semantic2(Scope *sc);
+    void semantic3(Scope *sc);
+    void inlineScan();
+    unsigned size(Loc loc);
+    static void alignmember(unsigned salign, unsigned size, unsigned *poffset);
+    Type *getType();
+    void addField(Scope *sc, VarDeclaration *v);
+    int isDeprecated();		// is aggregate deprecated?
+
+    void emitComment(Scope *sc);
+    void toDocBuffer(OutBuffer *buf);
+
+    // For access checking
+    virtual PROT getAccess(Dsymbol *smember);	// determine access to smember
+    int isFriendOf(AggregateDeclaration *cd);
+    int hasPrivateAccess(Dsymbol *smember);	// does smember have private access to members of this class?
+    void accessCheck(Loc loc, Scope *sc, Dsymbol *smember);
+
+    enum PROT prot();
+
+    // Back end
+    Symbol *stag;		// tag symbol for debug data
+    Symbol *sinit;
+    Symbol *toInitializer();
+
+    bool llvmInProgress;
+    llvm::Type* llvmType;
+    llvm::Value* llvmVtbl;
+    llvm::Constant* llvmInitZ;
+    virtual unsigned offsetToIndex(unsigned os); // converts a DMD field offsets to LLVM struct index
+
+    AggregateDeclaration *isAggregateDeclaration() { return this; }
+};
+
+struct AnonymousAggregateDeclaration : AggregateDeclaration
+{
+    AnonymousAggregateDeclaration()
+	: AggregateDeclaration(0, NULL)
+    {
+    }
+
+    AnonymousAggregateDeclaration *isAnonymousAggregateDeclaration() { return this; }
+};
+
+struct StructDeclaration : AggregateDeclaration
+{
+    int zeroInit;		// !=0 if initialize with 0 fill
+
+    StructDeclaration(Loc loc, Identifier *id);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    void semantic(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    char *mangle();
+    char *kind();
+    void toDocBuffer(OutBuffer *buf);
+
+    PROT getAccess(Dsymbol *smember);	// determine access to smember
+
+    void toObjFile();			// compile to .obj file
+    void toDt(dt_t **pdt);
+    void toDebug();			// to symbolic debug info
+
+    StructDeclaration *isStructDeclaration() { return this; }
+};
+
+struct UnionDeclaration : StructDeclaration
+{
+    UnionDeclaration(Loc loc, Identifier *id);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    char *kind();
+
+    UnionDeclaration *isUnionDeclaration() { return this; }
+};
+
+struct BaseClass
+{
+    Type *type;				// (before semantic processing)
+    enum PROT protection;		// protection for the base interface
+
+    ClassDeclaration *base;
+    int offset;				// 'this' pointer offset
+    Array vtbl;				// for interfaces: Array of FuncDeclaration's
+					// making up the vtbl[]
+
+    int baseInterfaces_dim;
+    BaseClass *baseInterfaces;		// if BaseClass is an interface, these
+					// are a copy of the InterfaceDeclaration::interfaces
+
+    BaseClass();
+    BaseClass(Type *type, enum PROT protection);
+
+    int fillVtbl(ClassDeclaration *cd, Array *vtbl, int newinstance);
+    void copyBaseInterfaces(BaseClasses *);
+};
+
+#define CLASSINFO_SIZE 	(0x3C+12)	// value of ClassInfo.size
+
+struct ClassDeclaration : AggregateDeclaration
+{
+    static ClassDeclaration *object;
+    static ClassDeclaration *classinfo;
+
+    ClassDeclaration *baseClass;	// NULL only if this is Object
+    CtorDeclaration *ctor;
+    CtorDeclaration *defaultCtor;	// default constructor
+    FuncDeclarations dtors;		// Array of destructors
+    FuncDeclaration *staticCtor;
+    FuncDeclaration *staticDtor;
+    Array vtbl;				// Array of FuncDeclaration's making up the vtbl[]
+    Array vtblFinal;			// More FuncDeclaration's that aren't in vtbl[]
+
+    BaseClasses baseclasses;		// Array of BaseClass's; first is super,
+					// rest are Interface's
+
+    int interfaces_dim;
+    BaseClass **interfaces;		// interfaces[interfaces_dim] for this class
+					// (does not include baseClass)
+
+    BaseClasses *vtblInterfaces;	// array of base interfaces that have
+					// their own vtbl[]
+
+    ClassInfoDeclaration *vclassinfo;	// the ClassInfo object for this ClassDeclaration
+    int com;				// !=0 if this is a COM class
+    int isauto;				// !=0 if this is an auto class
+    int isabstract;			// !=0 if abstract class
+
+    int isnested;			// !=0 if is nested
+    VarDeclaration *vthis;		// 'this' parameter if this class is nested
+
+    ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    void semantic(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    int isBaseOf2(ClassDeclaration *cd);
+
+    #define OFFSET_RUNTIME 0x76543210
+    virtual int isBaseOf(ClassDeclaration *cd, int *poffset);
+
+    Dsymbol *search(Loc, Identifier *ident, int flags);
+    FuncDeclaration *findFunc(Identifier *ident, TypeFunction *tf);
+    void interfaceSemantic(Scope *sc);
+    int isNested();
+    int isCOMclass();
+    int isAbstract();
+    virtual int vtblOffset();
+    char *kind();
+    char *mangle();
+    void toDocBuffer(OutBuffer *buf);
+
+    PROT getAccess(Dsymbol *smember);	// determine access to smember
+
+    void addLocalClass(ClassDeclarations *);
+
+    // Back end
+    void toObjFile();			// compile to .obj file
+    void toDebug();
+    unsigned baseVtblOffset(BaseClass *bc);
+    Symbol *toSymbol();
+    Symbol *toVtblSymbol();
+    void toDt(dt_t **pdt);
+    void toDt2(dt_t **pdt, ClassDeclaration *cd);
+
+    Symbol *vtblsym;
+
+    virtual unsigned offsetToIndex(unsigned os);
+
+    ClassDeclaration *isClassDeclaration() { return (ClassDeclaration *)this; }
+};
+
+struct InterfaceDeclaration : ClassDeclaration
+{
+    InterfaceDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    void semantic(Scope *sc);
+    int isBaseOf(ClassDeclaration *cd, int *poffset);
+    int isBaseOf(BaseClass *bc, int *poffset);
+    char *kind();
+    int vtblOffset();
+
+    void toObjFile();			// compile to .obj file
+    Symbol *toSymbol();
+
+    InterfaceDeclaration *isInterfaceDeclaration() { return this; }
+};
+
+#endif /* DMD_AGGREGATE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/array.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,220 @@
+
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <assert.h>
+
+#if _MSC_VER
+#include <malloc.h>
+#endif
+
+#if IN_GCC
+#include "gdc_alloca.h"
+#endif
+
+#if _WIN32
+#include <windows.h>
+#endif
+
+#ifndef _WIN32
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <utime.h>
+#endif
+
+#include "port.h"
+#include "root.h"
+#include "dchar.h"
+#include "mem.h"
+
+
+/********************************* Array ****************************/
+
+Array::Array()
+{
+    data = NULL;
+    dim = 0;
+    allocdim = 0;
+}
+
+Array::~Array()
+{
+    mem.free(data);
+}
+
+void Array::mark()
+{   unsigned u;
+
+    mem.mark(data);
+    for (u = 0; u < dim; u++)
+	mem.mark(data[u]);	// BUG: what if arrays of Object's?
+}
+
+void Array::reserve(unsigned nentries)
+{
+    //printf("Array::reserve: size = %d, offset = %d, nbytes = %d\n", size, offset, nbytes);
+    if (allocdim - dim < nentries)
+    {
+	allocdim = dim + nentries;
+	data = (void **)mem.realloc(data, allocdim * sizeof(*data));
+    }
+}
+
+void Array::setDim(unsigned newdim)
+{
+    if (dim < newdim)
+    {
+	reserve(newdim - dim);
+    }
+    dim = newdim;
+}
+
+void Array::fixDim()
+{
+    if (dim != allocdim)
+    {	data = (void **)mem.realloc(data, dim * sizeof(*data));
+	allocdim = dim;
+    }
+}
+
+void Array::push(void *ptr)
+{
+    reserve(1);
+    data[dim++] = ptr;
+}
+
+void *Array::pop()
+{
+    return data[--dim];
+}
+
+void Array::shift(void *ptr)
+{
+    reserve(1);
+    memmove(data + 1, data, dim * sizeof(*data));
+    data[0] = ptr;
+    dim++;
+}
+
+void Array::insert(unsigned index, void *ptr)
+{
+    reserve(1);
+    memmove(data + index + 1, data + index, (dim - index) * sizeof(*data));
+    data[index] = ptr;
+    dim++;
+}
+
+
+void Array::insert(unsigned index, Array *a)
+{
+    if (a)
+    {	unsigned d;
+
+	d = a->dim;
+	reserve(d);
+	if (dim != index)
+	    memmove(data + index + d, data + index, (dim - index) * sizeof(*data));
+	memcpy(data + index, a->data, d * sizeof(*data));
+	dim += d;
+    }
+}
+
+
+/***********************************
+ * Append array a to this array.
+ */
+
+void Array::append(Array *a)
+{
+    insert(dim, a);
+}
+
+void Array::remove(unsigned i)
+{
+    memmove(data + i, data + i + 1, (dim - i) * sizeof(data[0]));
+    dim--;
+}
+
+char *Array::toChars()
+{
+    unsigned len;
+    unsigned u;
+    char **buf;
+    char *str;
+    char *p;
+
+    buf = (char **)alloca(dim * sizeof(char *));
+    len = 2;
+    for (u = 0; u < dim; u++)
+    {
+	buf[u] = ((Object *)data[u])->toChars();
+	len += strlen(buf[u]) + 1;
+    }
+    str = (char *)mem.malloc(len);
+
+    str[0] = '[';
+    p = str + 1;
+    for (u = 0; u < dim; u++)
+    {
+	if (u)
+	    *p++ = ',';
+	len = strlen(buf[u]);
+	memcpy(p,buf[u],len);
+	p += len;
+    }
+    *p++ = ']';
+    *p = 0;
+    return str;
+}
+
+void Array::zero()
+{
+    memset(data,0,dim * sizeof(data[0]));
+}
+
+void *Array::tos()
+{
+    return dim ? data[dim - 1] : NULL;
+}
+
+int
+#if _WIN32
+  __cdecl
+#endif
+	Array_sort_compare(const void *x, const void *y)
+{
+    Object *ox = *(Object **)x;
+    Object *oy = *(Object **)y;
+
+    return ox->compare(oy);
+}
+
+void Array::sort()
+{
+    if (dim)
+    {
+	qsort(data, dim, sizeof(Object *), Array_sort_compare);
+    }
+}
+
+Array *Array::copy()
+{
+    Array *a = new Array();
+
+    a->setDim(dim);
+    memcpy(a->data, data, dim * sizeof(void *));
+    return a;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/arraytypes.h	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,51 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 2006-2007 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#ifndef DMD_ARRAYTYPES_H
+#define DMD_ARRAYTYPES_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+
+#include "root.h"
+
+struct Expression;
+struct Statement;
+struct BaseClass;
+struct TemplateParameter;
+struct FuncDeclaration;
+struct Identifier;
+struct Initializer;
+
+struct TemplateParameters : Array { };
+
+struct Expressions : Array { };
+
+struct Statements : Array { };
+
+struct BaseClasses : Array { };
+
+struct ClassDeclarations : Array { };
+
+struct Dsymbols : Array { };
+
+struct Objects : Array { };
+
+struct FuncDeclarations : Array { };
+
+struct Arguments : Array { };
+
+struct Identifiers : Array { };
+
+struct Initializers : Array { };
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/artistic.txt	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,117 @@
+
+
+
+
+			 The "Artistic License"
+
+				Preamble
+
+The intent of this document is to state the conditions under which a
+Package may be copied, such that the Copyright Holder maintains some
+semblance of artistic control over the development of the package,
+while giving the users of the package the right to use and distribute
+the Package in a more-or-less customary fashion, plus the right to make
+reasonable modifications.
+
+Definitions:
+
+	"Package" refers to the collection of files distributed by the
+	Copyright Holder, and derivatives of that collection of files
+	created through textual modification.
+
+	"Standard Version" refers to such a Package if it has not been
+	modified, or has been modified in accordance with the wishes
+	of the Copyright Holder as specified below.
+
+	"Copyright Holder" is whoever is named in the copyright or
+	copyrights for the package.
+
+	"You" is you, if you're thinking about copying or distributing
+	this Package.
+
+	"Reasonable copying fee" is whatever you can justify on the
+	basis of media cost, duplication charges, time of people involved,
+	and so on.  (You will not be required to justify it to the
+	Copyright Holder, but only to the computing community at large
+	as a market that must bear the fee.)
+
+	"Freely Available" means that no fee is charged for the item
+	itself, though there may be fees involved in handling the item.
+	It also means that recipients of the item may redistribute it
+	under the same conditions they received it.
+
+1. You may make and give away verbatim copies of the source form of the
+Standard Version of this Package without restriction, provided that you
+duplicate all of the original copyright notices and associated disclaimers.
+
+2. You may apply bug fixes, portability fixes and other modifications
+derived from the Public Domain or from the Copyright Holder.  A Package
+modified in such a way shall still be considered the Standard Version.
+
+3. You may otherwise modify your copy of this Package in any way, provided
+that you insert a prominent notice in each changed file stating how and
+when you changed that file, and provided that you do at least ONE of the
+following:
+
+    a) place your modifications in the Public Domain or otherwise make them
+    Freely Available, such as by posting said modifications to Usenet or
+    an equivalent medium, or placing the modifications on a major archive
+    site such as uunet.uu.net, or by allowing the Copyright Holder to include
+    your modifications in the Standard Version of the Package.
+
+    b) use the modified Package only within your corporation or organization.
+
+    c) rename any non-standard executables so the names do not conflict
+    with standard executables, which must also be provided, and provide
+    a separate manual page for each non-standard executable that clearly
+    documents how it differs from the Standard Version.
+
+    d) make other distribution arrangements with the Copyright Holder.
+
+4. You may distribute the programs of this Package in object code or
+executable form, provided that you do at least ONE of the following:
+
+    a) distribute a Standard Version of the executables and library files,
+    together with instructions (in the manual page or equivalent) on where
+    to get the Standard Version.
+
+    b) accompany the distribution with the machine-readable source of
+    the Package with your modifications.
+
+    c) give non-standard executables non-standard names, and clearly
+    document the differences in manual pages (or equivalent), together
+    with instructions on where to get the Standard Version.
+
+    d) make other distribution arrangements with the Copyright Holder.
+
+5. You may charge a reasonable copying fee for any distribution of this
+Package.  You may charge any fee you choose for support of this
+Package.  You may not charge a fee for this Package itself.  However,
+you may distribute this Package in aggregate with other (possibly
+commercial) programs as part of a larger (possibly commercial) software
+distribution provided that you do not advertise this Package as a
+product of your own.  You may embed this Package's interpreter within
+an executable of yours (by linking); this shall be construed as a mere
+form of aggregation, provided that the complete Standard Version of the
+interpreter is so embedded.
+
+6. The source code and object code supplied as input to or produced as
+output from the programs of this Package do not automatically fall
+under the copyright of this Package, but belong to whoever generated
+them, and may be sold commercially, and may be aggregated with this
+Package.
+
+7. Aggregation of this Package with a commercial distribution is always
+permitted provided that the use of this Package is embedded; that is,
+when no overt attempt is made to make this Package's interfaces visible
+to the end user of the commercial distribution.  Such use shall not be
+construed as a distribution of this Package.
+
+8. The name of the Copyright Holder may not be used to endorse or promote
+products derived from this software without specific prior written permission.
+
+9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+				The End
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/attrib.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,1249 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2007 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#if _WIN32 || IN_GCC || IN_LLVM
+#include "mem.h"
+#elif linux
+#include "../root/mem.h"
+#endif
+
+#include "init.h"
+#include "declaration.h"
+#include "attrib.h"
+#include "cond.h"
+#include "scope.h"
+#include "id.h"
+#include "expression.h"
+#include "dsymbol.h"
+#include "aggregate.h"
+#include "module.h"
+#include "parse.h"
+
+#include "../gen/enums.h"
+
+extern void obj_includelib(char *name);
+
+
+/********************************* AttribDeclaration ****************************/
+
+AttribDeclaration::AttribDeclaration(Array *decl)
+	: Dsymbol()
+{
+    this->decl = decl;
+}
+
+Array *AttribDeclaration::include(Scope *sc, ScopeDsymbol *sd)
+{
+    return decl;
+}
+
+int AttribDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum)
+{
+    unsigned i;
+    int m = 0;
+    Array *d = include(sc, sd);
+
+    if (d)
+    {
+	for (i = 0; i < d->dim; i++)
+	{   Dsymbol *s;
+
+	    s = (Dsymbol *)d->data[i];
+	    m |= s->addMember(sc, sd, m | memnum);
+	}
+    }
+    return m;
+}
+
+void AttribDeclaration::semantic(Scope *sc)
+{
+    Array *d = include(sc, NULL);
+
+    //printf("\tAttribDeclaration::semantic '%s'\n",toChars());
+    if (d)
+    {
+	for (unsigned i = 0; i < d->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)d->data[i];
+
+	    s->semantic(sc);
+	}
+    }
+}
+
+void AttribDeclaration::semantic2(Scope *sc)
+{
+    unsigned i;
+    Array *d = include(sc, NULL);
+
+    if (d)
+    {
+	for (i = 0; i < d->dim; i++)
+	{   Dsymbol *s;
+
+	    s = (Dsymbol *)d->data[i];
+	    s->semantic2(sc);
+	}
+    }
+}
+
+void AttribDeclaration::semantic3(Scope *sc)
+{
+    unsigned i;
+    Array *d = include(sc, NULL);
+
+    if (d)
+    {
+	for (i = 0; i < d->dim; i++)
+	{   Dsymbol *s;
+
+	    s = (Dsymbol *)d->data[i];
+	    s->semantic3(sc);
+	}
+    }
+}
+
+void AttribDeclaration::inlineScan()
+{
+    unsigned i;
+    Array *d = include(NULL, NULL);
+
+    if (d)
+    {
+	for (i = 0; i < d->dim; i++)
+	{   Dsymbol *s;
+
+	    s = (Dsymbol *)d->data[i];
+	    //printf("AttribDeclaration::inlineScan %s\n", s->toChars());
+	    s->inlineScan();
+	}
+    }
+}
+
+void AttribDeclaration::addComment(unsigned char *comment)
+{
+    if (comment)
+    {
+	unsigned i;
+	Array *d = include(NULL, NULL);
+
+	if (d)
+	{
+	    for (i = 0; i < d->dim; i++)
+	    {   Dsymbol *s;
+
+		s = (Dsymbol *)d->data[i];
+		//printf("AttribDeclaration::addComment %s\n", s->toChars());
+		s->addComment(comment);
+	    }
+	}
+    }
+}
+
+void AttribDeclaration::emitComment(Scope *sc)
+{
+    //printf("AttribDeclaration::emitComment(sc = %p)\n", sc);
+
+    /* If generating doc comment, skip this because if we're inside
+     * a template, then include(NULL, NULL) will fail.
+     */
+//    if (sc->docbuf)
+//	return;
+
+    unsigned i;
+    Array *d = include(NULL, NULL);
+
+    if (d)
+    {
+	for (i = 0; i < d->dim; i++)
+	{   Dsymbol *s;
+
+	    s = (Dsymbol *)d->data[i];
+	    //printf("AttribDeclaration::emitComment %s\n", s->toChars());
+	    s->emitComment(sc);
+	}
+    }
+}
+
+void AttribDeclaration::toObjFile()
+{
+    unsigned i;
+    Array *d = include(NULL, NULL);
+
+    if (d)
+    {
+	for (i = 0; i < d->dim; i++)
+	{   Dsymbol *s;
+
+	    s = (Dsymbol *)d->data[i];
+	    s->toObjFile();
+	}
+    }
+}
+
+int AttribDeclaration::hasPointers()
+{
+    Array *d = include(NULL, NULL);
+
+    if (d)
+    {
+	for (size_t i = 0; i < d->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)d->data[i];
+	    if (s->hasPointers())
+		return 1;
+	}
+    }
+    return 0;
+}
+
+char *AttribDeclaration::kind()
+{
+    return "attribute";
+}
+
+int AttribDeclaration::oneMember(Dsymbol **ps)
+{
+    Array *d = include(NULL, NULL);
+
+    return Dsymbol::oneMembers(d, ps);
+}
+
+void AttribDeclaration::checkCtorConstInit()
+{
+    unsigned i;
+    Array *d = include(NULL, NULL);
+
+    if (d)
+    {
+	for (i = 0; i < d->dim; i++)
+	{   Dsymbol *s;
+
+	    s = (Dsymbol *)d->data[i];
+	    s->checkCtorConstInit();
+	}
+    }
+}
+
+/****************************************
+ */
+
+void AttribDeclaration::addLocalClass(ClassDeclarations *aclasses)
+{   unsigned i;
+    Array *d = include(NULL, NULL);
+
+    if (d)
+    {
+	for (i = 0; i < d->dim; i++)
+	{   Dsymbol *s;
+
+	    s = (Dsymbol *)d->data[i];
+	    s->addLocalClass(aclasses);
+	}
+    }
+}
+
+
+void AttribDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    if (decl)
+    {
+	buf->writenl();
+	buf->writeByte('{');
+	buf->writenl();
+	for (unsigned i = 0; i < decl->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)decl->data[i];
+
+	    buf->writestring("    ");
+	    s->toCBuffer(buf, hgs);
+	}
+	buf->writeByte('}');
+    }
+    else
+	buf->writeByte(';');
+    buf->writenl();
+}
+
+/************************* StorageClassDeclaration ****************************/
+
+StorageClassDeclaration::StorageClassDeclaration(unsigned stc, Array *decl)
+	: AttribDeclaration(decl)
+{
+    this->stc = stc;
+}
+
+Dsymbol *StorageClassDeclaration::syntaxCopy(Dsymbol *s)
+{
+    StorageClassDeclaration *scd;
+
+    assert(!s);
+    scd = new StorageClassDeclaration(stc, Dsymbol::arraySyntaxCopy(decl));
+    return scd;
+}
+
+void StorageClassDeclaration::semantic(Scope *sc)
+{
+    if (decl)
+    {	unsigned stc_save = sc->stc;
+
+	if (stc & (STCauto | STCscope | STCstatic | STCextern))
+	    sc->stc &= ~(STCauto | STCscope | STCstatic | STCextern);
+	sc->stc |= stc;
+	for (unsigned i = 0; i < decl->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)decl->data[i];
+
+	    s->semantic(sc);
+	}
+	sc->stc = stc_save;
+    }
+    else
+	sc->stc = stc;
+}
+
+void StorageClassDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    struct SCstring
+    {
+	int stc;
+	enum TOK tok;
+    };
+
+    static SCstring table[] =
+    {
+	{ STCauto,         TOKauto },
+	{ STCscope,        TOKscope },
+	{ STCstatic,       TOKstatic },
+	{ STCextern,       TOKextern },
+	{ STCconst,        TOKconst },
+	{ STCfinal,        TOKfinal },
+	{ STCabstract,     TOKabstract },
+	{ STCsynchronized, TOKsynchronized },
+	{ STCdeprecated,   TOKdeprecated },
+	{ STCoverride,     TOKoverride },
+    };
+
+    int written = 0;
+    for (int i = 0; i < sizeof(table)/sizeof(table[0]); i++)
+    {
+	if (stc & table[i].stc)
+	{
+	    if (written)
+		buf->writeByte(' ');
+	    written = 1;
+	    buf->writestring(Token::toChars(table[i].tok));
+	}
+    }
+
+    AttribDeclaration::toCBuffer(buf, hgs);
+}
+
+/********************************* LinkDeclaration ****************************/
+
+LinkDeclaration::LinkDeclaration(enum LINK p, Array *decl)
+	: AttribDeclaration(decl)
+{
+    //printf("LinkDeclaration(linkage = %d, decl = %p)\n", p, decl);
+    linkage = p;
+}
+
+Dsymbol *LinkDeclaration::syntaxCopy(Dsymbol *s)
+{
+    LinkDeclaration *ld;
+
+    assert(!s);
+    ld = new LinkDeclaration(linkage, Dsymbol::arraySyntaxCopy(decl));
+    return ld;
+}
+
+void LinkDeclaration::semantic(Scope *sc)
+{
+    //printf("LinkDeclaration::semantic(linkage = %d, decl = %p)\n", linkage, decl);
+    if (decl)
+    {	enum LINK linkage_save = sc->linkage;
+
+	sc->linkage = linkage;
+	for (unsigned i = 0; i < decl->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)decl->data[i];
+
+	    s->semantic(sc);
+	}
+	sc->linkage = linkage_save;
+    }
+    else
+    {
+	sc->linkage = linkage;
+    }
+}
+
+void LinkDeclaration::semantic3(Scope *sc)
+{
+    //printf("LinkDeclaration::semantic3(linkage = %d, decl = %p)\n", linkage, decl);
+    if (decl)
+    {	enum LINK linkage_save = sc->linkage;
+
+	sc->linkage = linkage;
+	for (unsigned i = 0; i < decl->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)decl->data[i];
+
+	    s->semantic3(sc);
+	}
+	sc->linkage = linkage_save;
+    }
+    else
+    {
+	sc->linkage = linkage;
+    }
+}
+
+void LinkDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{   char *p;
+
+    switch (linkage)
+    {
+	case LINKd:		p = "D";		break;
+	case LINKc:		p = "C";		break;
+	case LINKcpp:		p = "C++";		break;
+	case LINKwindows:	p = "Windows";		break;
+	case LINKpascal:	p = "Pascal";		break;
+	default:
+	    assert(0);
+	    break;
+    }
+    buf->writestring("extern (");
+    buf->writestring(p);
+    buf->writestring(") ");
+    AttribDeclaration::toCBuffer(buf, hgs);
+}
+
+char *LinkDeclaration::toChars()
+{
+    return "extern ()";
+}
+
+/********************************* ProtDeclaration ****************************/
+
+ProtDeclaration::ProtDeclaration(enum PROT p, Array *decl)
+	: AttribDeclaration(decl)
+{
+    protection = p;
+    //printf("decl = %p\n", decl);
+}
+
+Dsymbol *ProtDeclaration::syntaxCopy(Dsymbol *s)
+{
+    ProtDeclaration *pd;
+
+    assert(!s);
+    pd = new ProtDeclaration(protection, Dsymbol::arraySyntaxCopy(decl));
+    return pd;
+}
+
+void ProtDeclaration::semantic(Scope *sc)
+{
+    if (decl)
+    {	enum PROT protection_save = sc->protection;
+	int explicitProtection_save = sc->explicitProtection;
+
+	sc->protection = protection;
+	sc->explicitProtection = 1;
+	for (unsigned i = 0; i < decl->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)decl->data[i];
+
+	    s->semantic(sc);
+	}
+	sc->protection = protection_save;
+	sc->explicitProtection = explicitProtection_save;
+    }
+    else
+    {	sc->protection = protection;
+	sc->explicitProtection = 1;
+    }
+}
+
+void ProtDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{   char *p;
+
+    switch (protection)
+    {
+	case PROTprivate:	p = "private";		break;
+	case PROTpackage:	p = "package";		break;
+	case PROTprotected:	p = "protected";	break;
+	case PROTpublic:	p = "public";		break;
+	case PROTexport:	p = "export";		break;
+	default:
+	    assert(0);
+	    break;
+    }
+    buf->writestring(p);
+    AttribDeclaration::toCBuffer(buf, hgs);
+}
+
+/********************************* AlignDeclaration ****************************/
+
+AlignDeclaration::AlignDeclaration(unsigned sa, Array *decl)
+	: AttribDeclaration(decl)
+{
+    salign = sa;
+}
+
+Dsymbol *AlignDeclaration::syntaxCopy(Dsymbol *s)
+{
+    AlignDeclaration *ad;
+
+    assert(!s);
+    ad = new AlignDeclaration(salign, Dsymbol::arraySyntaxCopy(decl));
+    return ad;
+}
+
+void AlignDeclaration::semantic(Scope *sc)
+{
+    //printf("\tAlignDeclaration::semantic '%s'\n",toChars());
+    if (decl)
+    {	unsigned salign_save = sc->structalign;
+
+	sc->structalign = salign;
+	for (unsigned i = 0; i < decl->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)decl->data[i];
+
+	    s->semantic(sc);
+	}
+	sc->structalign = salign_save;
+    }
+    else
+	sc->structalign = salign;
+}
+
+
+void AlignDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->printf("align (%d)", salign);
+    AttribDeclaration::toCBuffer(buf, hgs);
+}
+
+/********************************* AnonDeclaration ****************************/
+
+AnonDeclaration::AnonDeclaration(Loc loc, int isunion, Array *decl)
+	: AttribDeclaration(decl)
+{
+    this->loc = loc;
+    this->isunion = isunion;
+    this->scope = NULL;
+    this->sem = 0;
+}
+
+Dsymbol *AnonDeclaration::syntaxCopy(Dsymbol *s)
+{
+    AnonDeclaration *ad;
+
+    assert(!s);
+    ad = new AnonDeclaration(loc, isunion, Dsymbol::arraySyntaxCopy(decl));
+    return ad;
+}
+
+void AnonDeclaration::semantic(Scope *sc)
+{
+    //printf("\tAnonDeclaration::semantic %s %p\n", isunion ? "union" : "struct", this);
+
+    Scope *scx = NULL;
+    if (scope)
+    {   sc = scope;
+	scx = scope;
+	scope = NULL;
+    }
+
+    assert(sc->parent);
+
+    Dsymbol *parent = sc->parent->pastMixin();
+    AggregateDeclaration *ad = parent->isAggregateDeclaration();
+
+    if (!ad || (!ad->isStructDeclaration() && !ad->isClassDeclaration()))
+    {
+	error("can only be a part of an aggregate");
+	return;
+    }
+
+    if (decl)
+    {
+	AnonymousAggregateDeclaration aad;
+	int adisunion;
+
+	if (sc->anonAgg)
+	{   ad = sc->anonAgg;
+	    adisunion = sc->inunion;
+	}
+	else
+	    adisunion = ad->isUnionDeclaration() != NULL;
+
+//	printf("\tsc->anonAgg = %p\n", sc->anonAgg);
+//	printf("\tad  = %p\n", ad);
+//	printf("\taad = %p\n", &aad);
+
+	sc = sc->push();
+	sc->anonAgg = &aad;
+	sc->stc &= ~(STCauto | STCscope | STCstatic);
+	sc->inunion = isunion;
+	sc->offset = 0;
+	sc->flags = 0;
+	aad.structalign = sc->structalign;
+	aad.parent = ad;
+
+	for (unsigned i = 0; i < decl->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)decl->data[i];
+
+	    s->semantic(sc);
+	    if (isunion)
+		sc->offset = 0;
+	    if (aad.sizeok == 2)
+	    {
+		break;
+	    }
+	}
+	sc = sc->pop();
+
+	// If failed due to forward references, unwind and try again later
+	if (aad.sizeok == 2)
+	{
+	    ad->sizeok = 2;
+	    //printf("\tsetting ad->sizeok %p to 2\n", ad);
+	    if (!sc->anonAgg)
+	    {
+		scope = scx ? scx : new Scope(*sc);
+		scope->setNoFree();
+		scope->module->addDeferredSemantic(this);
+	    }
+	    //printf("\tforward reference %p\n", this);
+	    return;
+	}
+	if (sem == 0)
+	{   Module::dprogress++;
+	    sem = 1;
+	    //printf("\tcompleted %p\n", this);
+	}
+	else
+	    ;//printf("\talready completed %p\n", this);
+
+	// 0 sized structs are set to 1 byte
+	if (aad.structsize == 0)
+	{
+	    aad.structsize = 1;
+	    aad.alignsize = 1;
+	}
+
+	// Align size of anonymous aggregate
+//printf("aad.structalign = %d, aad.alignsize = %d, sc->offset = %d\n", aad.structalign, aad.alignsize, sc->offset);
+	ad->alignmember(aad.structalign, aad.alignsize, &sc->offset);
+	//ad->structsize = sc->offset;
+//printf("sc->offset = %d\n", sc->offset);
+
+	// Add members of aad to ad
+	//printf("\tadding members of aad to '%s'\n", ad->toChars());
+	for (unsigned i = 0; i < aad.fields.dim; i++)
+	{
+	    VarDeclaration *v = (VarDeclaration *)aad.fields.data[i];
+
+	    v->offset += sc->offset;
+	    ad->fields.push(v);
+	}
+
+	// Add size of aad to ad
+	if (adisunion)
+	{
+	    if (aad.structsize > ad->structsize)
+		ad->structsize = aad.structsize;
+	    sc->offset = 0;
+	}
+	else
+	{
+	    ad->structsize = sc->offset + aad.structsize;
+	    sc->offset = ad->structsize;
+	}
+
+	if (ad->alignsize < aad.alignsize)
+	    ad->alignsize = aad.alignsize;
+    }
+}
+
+
+void AnonDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->printf(isunion ? "union" : "struct");
+    buf->writestring("\n{\n");
+    if (decl)
+    {
+	for (unsigned i = 0; i < decl->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)decl->data[i];
+
+	    //buf->writestring("    ");
+	    s->toCBuffer(buf, hgs);
+	}
+    }
+    buf->writestring("}\n");
+}
+
+char *AnonDeclaration::kind()
+{
+    return (char *)(isunion ? "anonymous union" : "anonymous struct");
+}
+
+/********************************* PragmaDeclaration ****************************/
+
+PragmaDeclaration::PragmaDeclaration(Loc loc, Identifier *ident, Expressions *args, Array *decl)
+	: AttribDeclaration(decl)
+{
+    this->loc = loc;
+    this->ident = ident;
+    this->args = args;
+}
+
+Dsymbol *PragmaDeclaration::syntaxCopy(Dsymbol *s)
+{
+    PragmaDeclaration *pd;
+
+    assert(!s);
+    pd = new PragmaDeclaration(loc, ident,
+	Expression::arraySyntaxCopy(args), Dsymbol::arraySyntaxCopy(decl));
+    return pd;
+}
+
+void PragmaDeclaration::semantic(Scope *sc)
+{   // Should be merged with PragmaStatement
+
+#if IN_LLVM
+    int llvm_internal = 0;
+    char* llvm_str1 = NULL;
+    
+#endif
+    
+    //printf("\tPragmaDeclaration::semantic '%s'\n",toChars());
+    if (ident == Id::msg)
+    {
+	if (args)
+	{
+	    for (size_t i = 0; i < args->dim; i++)
+	    {
+		Expression *e = (Expression *)args->data[i];
+
+		e = e->semantic(sc);
+		e = e->optimize(WANTvalue | WANTinterpret);
+		if (e->op == TOKstring)
+		{
+		    StringExp *se = (StringExp *)e;
+		    fprintf(stdmsg, "%.*s", (int)se->len, se->string);
+		}
+		else
+		    error("string expected for message, not '%s'", e->toChars());
+	    }
+	    fprintf(stdmsg, "\n");
+	}
+	goto Lnodecl;
+    }
+    else if (ident == Id::lib)
+    {
+	if (!args || args->dim != 1)
+	    error("string expected for library name");
+	else
+	{
+	    Expression *e = (Expression *)args->data[0];
+
+	    e = e->semantic(sc);
+	    e = e->optimize(WANTvalue | WANTinterpret);
+	    args->data[0] = (void *)e;
+	    if (e->op != TOKstring)
+		error("string expected for library name, not '%s'", e->toChars());
+	    else if (global.params.verbose)
+	    {
+		StringExp *se = (StringExp *)e;
+		char *name = (char *)mem.malloc(se->len + 1);
+		memcpy(name, se->string, se->len);
+		name[se->len] = 0;
+		printf("library   %s\n", name);
+		mem.free(name);
+	    }
+	}
+	goto Lnodecl;
+    }
+#if IN_GCC
+    else if (ident == Id::GNU_asm)
+    {
+	if (! args || args->dim != 2)
+	    error("identifier and string expected for asm name");
+	else
+	{
+	    Expression *e;
+	    Declaration *d = NULL;
+	    StringExp *s = NULL;
+
+	    e = (Expression *)args->data[0];
+	    e = e->semantic(sc);
+	    if (e->op == TOKvar)
+	    {
+		d = ((VarExp *)e)->var;
+		if (! d->isFuncDeclaration() && ! d->isVarDeclaration())
+		    d = NULL;
+	    }
+	    if (!d)
+		error("first argument of GNU_asm must be a function or variable declaration");
+
+	    e = (Expression *)args->data[1];
+	    e = e->semantic(sc);
+	    e = e->optimize(WANTvalue);
+	    if (e->op == TOKstring && ((StringExp *)e)->sz == 1)
+		s = ((StringExp *)e);
+	    else
+		error("second argument of GNU_asm must be a char string");
+
+	    if (d && s)
+		d->c_ident = Lexer::idPool((char*) s->string);
+	}
+	goto Lnodecl;
+    }
+#endif
+#if IN_LLVM
+    else if (ident == Id::LLVM_internal)
+    {
+        if (!args || args->dim < 1 || args->dim > 2)
+            error("needs 1-3 parameters");
+        else if (!decl || decl->dim < 1)
+            error("must apply to at least one declaration");
+        else
+        {
+            Expression *e;
+            StringExp *s = NULL;
+
+            e = (Expression *)args->data[0];
+            e = e->semantic(sc);
+            e = e->optimize(WANTvalue);
+            if (e->op == TOKstring && (s = (StringExp *)e))
+            {
+                char* str = (char*)s->string;
+                if (strcmp(str,"intrinsic")==0) {
+                    llvm_internal = LLVMintrinsic;
+                    assert(args->dim == 2);
+                }
+                else if (strcmp(str,"null")==0) {
+                    llvm_internal = LLVMnull;
+                    assert(args->dim == 1);
+                }
+                else if (strcmp(str,"mangle")==0) {
+                    llvm_internal = LLVMmangle;
+                    assert(args->dim == 2);
+                }
+                else if (strcmp(str,"bind")==0) {
+                    llvm_internal = LLVMbind;
+                    assert(args->dim == 2);
+                }
+                else {
+                    error("unknown pragma command: %s", str);
+                }
+            }
+            else
+            error("1st argument must be a string");
+            
+            if (llvm_internal)
+            switch (llvm_internal)
+            {
+            case LLVMintrinsic:
+            case LLVMmangle:
+            case LLVMbind:
+                e = (Expression *)args->data[1];
+                e = e->semantic(sc);
+                e = e->optimize(WANTvalue);
+                if (e->op == TOKstring && (s = (StringExp *)e)) {
+                    llvm_str1 = (char*)s->string;
+                }
+                else
+                error("2nd argument must be a string");
+                break;
+            
+            case LLVMnull:
+                break;
+            
+            default:
+                assert(0);
+            }
+        }
+    }
+#endif
+    else
+	error("unrecognized pragma(%s)", ident->toChars());
+
+    if (decl)
+    {
+	for (unsigned i = 0; i < decl->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)decl->data[i];
+
+	    s->semantic(sc);
+        
+#if IN_LLVM
+        if (llvm_internal)
+        {
+            switch(llvm_internal)
+            {
+            case LLVMintrinsic:
+            case LLVMmangle:
+                if (FuncDeclaration* fd = s->isFuncDeclaration()) {
+                    fd->llvmInternal = llvm_internal;
+                    fd->llvmInternal1 = llvm_str1;
+                }
+                else {
+                    error("may only be used on function declarations");
+                    assert(0);
+                }
+                break;
+            
+            case LLVMnull:
+                if (StaticCtorDeclaration* sd = s->isStaticCtorDeclaration()) {
+                    sd->llvmInternal = llvm_internal;
+                }
+                else {
+                    error("may only be used on static constructors");
+                    assert(0);
+                }
+                break;
+            
+            case LLVMbind:
+                if (VarDeclaration* vd = s->isVarDeclaration()) {
+                    vd->llvmInternal = llvm_internal;
+                    vd->llvmInternal1 = llvm_str1;
+                }
+                else {
+                    error("may only be used on var declarations");
+                    assert(0);
+                }
+                break;
+            
+            default:
+                assert(0 && "invalid LLVM_internal pragma got through :/");
+            }
+        }
+        
+#endif
+    }
+    }
+    return;
+
+Lnodecl:
+    if (decl)
+	error("pragma is missing closing ';'");
+}
+
+int PragmaDeclaration::oneMember(Dsymbol **ps)
+{
+    *ps = NULL;
+    return TRUE;
+}
+
+char *PragmaDeclaration::kind()
+{
+    return "pragma";
+}
+
+void PragmaDeclaration::toObjFile()
+{
+    if (ident == Id::lib)
+    {
+	assert(args && args->dim == 1);
+
+	Expression *e = (Expression *)args->data[0];
+
+	assert(e->op == TOKstring);
+
+	StringExp *se = (StringExp *)e;
+	char *name = (char *)mem.malloc(se->len + 1);
+	memcpy(name, se->string, se->len);
+	name[se->len] = 0;
+	obj_includelib(name);
+    }
+    AttribDeclaration::toObjFile();
+}
+
+void PragmaDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->printf("pragma(%s", ident->toChars());
+    if (args)
+    {
+	for (size_t i = 0; i < args->dim; i++)
+	{
+	    Expression *e = (Expression *)args->data[i];
+
+	    buf->writestring(", ");
+	    e->toCBuffer(buf, hgs);
+	}
+    }
+    buf->writestring(")");
+    AttribDeclaration::toCBuffer(buf, hgs);
+}
+
+
+/********************************* ConditionalDeclaration ****************************/
+
+ConditionalDeclaration::ConditionalDeclaration(Condition *condition, Array *decl, Array *elsedecl)
+	: AttribDeclaration(decl)
+{
+    //printf("ConditionalDeclaration::ConditionalDeclaration()\n");
+    this->condition = condition;
+    this->elsedecl = elsedecl;
+}
+
+Dsymbol *ConditionalDeclaration::syntaxCopy(Dsymbol *s)
+{
+    ConditionalDeclaration *dd;
+
+    assert(!s);
+    dd = new ConditionalDeclaration(condition->syntaxCopy(),
+	Dsymbol::arraySyntaxCopy(decl),
+	Dsymbol::arraySyntaxCopy(elsedecl));
+    return dd;
+}
+
+
+int ConditionalDeclaration::oneMember(Dsymbol **ps)
+{
+    //printf("ConditionalDeclaration::oneMember(), inc = %d\n", condition->inc);
+    if (condition->inc)
+    {
+	Array *d = condition->include(NULL, NULL) ? decl : elsedecl;
+	return Dsymbol::oneMembers(d, ps);
+    }
+    *ps = NULL;
+    return TRUE;
+}
+
+void ConditionalDeclaration::emitComment(Scope *sc)
+{
+    //printf("ConditionalDeclaration::emitComment(sc = %p)\n", sc);
+    if (condition->inc)
+    {
+	AttribDeclaration::emitComment(sc);
+    }
+}
+
+// Decide if 'then' or 'else' code should be included
+
+Array *ConditionalDeclaration::include(Scope *sc, ScopeDsymbol *sd)
+{
+    //printf("ConditionalDeclaration::include()\n");
+    assert(condition);
+    return condition->include(sc, sd) ? decl : elsedecl;
+}
+
+
+void ConditionalDeclaration::addComment(unsigned char *comment)
+{
+    /* Because addComment is called by the parser, if we called
+     * include() it would define a version before it was used.
+     * But it's no problem to drill down to both decl and elsedecl,
+     * so that's the workaround.
+     */
+
+    if (comment)
+    {
+	Array *d = decl;
+
+	for (int j = 0; j < 2; j++)
+	{
+	    if (d)
+	    {
+		for (unsigned i = 0; i < d->dim; i++)
+		{   Dsymbol *s;
+
+		    s = (Dsymbol *)d->data[i];
+		    //printf("ConditionalDeclaration::addComment %s\n", s->toChars());
+		    s->addComment(comment);
+		}
+	    }
+	    d = elsedecl;
+	}
+    }
+}
+
+void ConditionalDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    condition->toCBuffer(buf, hgs);
+    if (decl || elsedecl)
+    {
+	buf->writenl();
+	buf->writeByte('{');
+	buf->writenl();
+	if (decl)
+	{
+	    for (unsigned i = 0; i < decl->dim; i++)
+	    {
+		Dsymbol *s = (Dsymbol *)decl->data[i];
+
+		buf->writestring("    ");
+		s->toCBuffer(buf, hgs);
+	    }
+	}
+	buf->writeByte('}');
+	if (elsedecl)
+	{
+	    buf->writenl();
+	    buf->writestring("else");
+	    buf->writenl();
+	    buf->writeByte('{');
+	    buf->writenl();
+	    for (unsigned i = 0; i < elsedecl->dim; i++)
+	    {
+		Dsymbol *s = (Dsymbol *)elsedecl->data[i];
+
+		buf->writestring("    ");
+		s->toCBuffer(buf, hgs);
+	    }
+	    buf->writeByte('}');
+	}
+    }
+    else
+	buf->writeByte(':');
+    buf->writenl();
+}
+
+/***************************** StaticIfDeclaration ****************************/
+
+StaticIfDeclaration::StaticIfDeclaration(Condition *condition,
+	Array *decl, Array *elsedecl)
+	: ConditionalDeclaration(condition, decl, elsedecl)
+{
+    //printf("StaticIfDeclaration::StaticIfDeclaration()\n");
+    sd = NULL;
+    addisdone = 0;
+}
+
+
+Dsymbol *StaticIfDeclaration::syntaxCopy(Dsymbol *s)
+{
+    StaticIfDeclaration *dd;
+
+    assert(!s);
+    dd = new StaticIfDeclaration(condition->syntaxCopy(),
+	Dsymbol::arraySyntaxCopy(decl),
+	Dsymbol::arraySyntaxCopy(elsedecl));
+    return dd;
+}
+
+
+int StaticIfDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum)
+{
+    /* This is deferred until semantic(), so that
+     * expressions in the condition can refer to declarations
+     * in the same scope, such as:
+     *
+     * template Foo(int i)
+     * {
+     *     const int j = i + 1;
+     *     static if (j == 3)
+     *         const int k;
+     * }
+     */
+    this->sd = sd;
+    int m = 0;
+
+    if (memnum == 0)
+    {	m = AttribDeclaration::addMember(sc, sd, memnum);
+	addisdone = 1;
+    }
+    return m;
+}
+
+
+void StaticIfDeclaration::semantic(Scope *sc)
+{
+    Array *d = include(sc, sd);
+
+    //printf("\tStaticIfDeclaration::semantic '%s'\n",toChars());
+    if (d)
+    {
+	if (!addisdone)
+	{   AttribDeclaration::addMember(sc, sd, 1);
+	    addisdone = 1;
+	}
+
+	for (unsigned i = 0; i < d->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)d->data[i];
+
+	    s->semantic(sc);
+	}
+    }
+}
+
+char *StaticIfDeclaration::kind()
+{
+    return "static if";
+}
+
+
+/***************************** CompileDeclaration *****************************/
+
+CompileDeclaration::CompileDeclaration(Loc loc, Expression *exp)
+    : AttribDeclaration(NULL)
+{
+    this->exp = exp;
+    this->sd = NULL;
+}
+
+Dsymbol *CompileDeclaration::syntaxCopy(Dsymbol *s)
+{
+    //printf("CompileDeclaration::syntaxCopy('%s')\n", toChars());
+    CompileDeclaration *sc = new CompileDeclaration(loc, exp->syntaxCopy());
+    return sc;
+}
+
+int CompileDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum)
+{
+    this->sd = sd;
+    return memnum;
+}
+
+void CompileDeclaration::semantic(Scope *sc)
+{
+    //printf("CompileDeclaration::semantic()\n");
+    exp = exp->semantic(sc);
+    exp = resolveProperties(sc, exp);
+    exp = exp->optimize(WANTvalue | WANTinterpret);
+    if (exp->op != TOKstring)
+    {	error("argument to mixin must be a string, not (%s)", exp->toChars());
+	return;
+    }
+    StringExp *se = (StringExp *)exp;
+    se = se->toUTF8(sc);
+    Parser p(sc->module, (unsigned char *)se->string, se->len, 0);
+    p.loc = loc;
+    p.nextToken();
+    decl = p.parseDeclDefs(0);
+    if (p.token.value != TOKeof)
+    {
+	error("incomplete mixin declaration (%s)", se->toChars());
+    }
+
+    AttribDeclaration::addMember(sc, sd, 0);
+    AttribDeclaration::semantic(sc);
+}
+
+void CompileDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("mixin(");
+    exp->toCBuffer(buf, hgs);
+    buf->writestring(");");
+    buf->writenl();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/attrib.h	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,165 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2007 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#ifndef DMD_ATTRIB_H
+#define DMD_ATTRIB_H
+
+#ifdef __DMC__
+#pragma once
+#endif /* __DMC__ */
+
+#include "dsymbol.h"
+
+struct Expression;
+struct Statement;
+struct LabelDsymbol;
+struct Initializer;
+struct Module;
+struct Condition;
+#ifdef _DH
+struct HdrGenState;
+#endif
+
+/**************************************************************/
+
+struct AttribDeclaration : Dsymbol
+{
+    Array *decl;	// array of Dsymbol's
+
+    AttribDeclaration(Array *decl);
+    virtual Array *include(Scope *sc, ScopeDsymbol *s);
+    int addMember(Scope *sc, ScopeDsymbol *s, int memnum);
+    void semantic(Scope *sc);
+    void semantic2(Scope *sc);
+    void semantic3(Scope *sc);
+    void inlineScan();
+    void addComment(unsigned char *comment);
+    void emitComment(Scope *sc);
+    char *kind();
+    int oneMember(Dsymbol **ps);
+    int hasPointers();
+    void checkCtorConstInit();
+    void addLocalClass(ClassDeclarations *);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    AttribDeclaration *isAttribDeclaration() { return this; }
+
+    void toObjFile();			// compile to .obj file
+};
+
+struct StorageClassDeclaration: AttribDeclaration
+{
+    unsigned stc;
+
+    StorageClassDeclaration(unsigned stc, Array *decl);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    void semantic(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+};
+
+struct LinkDeclaration : AttribDeclaration
+{
+    enum LINK linkage;
+
+    LinkDeclaration(enum LINK p, Array *decl);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    void semantic(Scope *sc);
+    void semantic3(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    char *toChars();
+};
+
+struct ProtDeclaration : AttribDeclaration
+{
+    enum PROT protection;
+
+    ProtDeclaration(enum PROT p, Array *decl);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    void semantic(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+};
+
+struct AlignDeclaration : AttribDeclaration
+{
+    unsigned salign;
+
+    AlignDeclaration(unsigned sa, Array *decl);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    void semantic(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+};
+
+struct AnonDeclaration : AttribDeclaration
+{
+    int isunion;
+    Scope *scope;		// !=NULL means context to use
+    int sem;			// 1 if successful semantic()
+
+    AnonDeclaration(Loc loc, int isunion, Array *decl);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    void semantic(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    char *kind();
+};
+
+struct PragmaDeclaration : AttribDeclaration
+{
+    Expressions *args;		// array of Expression's
+
+    PragmaDeclaration(Loc loc, Identifier *ident, Expressions *args, Array *decl);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    void semantic(Scope *sc);
+    int oneMember(Dsymbol **ps);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+    char *kind();
+    void toObjFile();			// compile to .obj file
+};
+
+struct ConditionalDeclaration : AttribDeclaration
+{
+    Condition *condition;
+    Array *elsedecl;	// array of Dsymbol's for else block
+
+    ConditionalDeclaration(Condition *condition, Array *decl, Array *elsedecl);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    int oneMember(Dsymbol **ps);
+    void emitComment(Scope *sc);
+    Array *include(Scope *sc, ScopeDsymbol *s);
+    void addComment(unsigned char *comment);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+};
+
+struct StaticIfDeclaration : ConditionalDeclaration
+{
+    ScopeDsymbol *sd;
+    int addisdone;
+
+    StaticIfDeclaration(Condition *condition, Array *decl, Array *elsedecl);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    int addMember(Scope *sc, ScopeDsymbol *s, int memnum);
+    void semantic(Scope *sc);
+    char *kind();
+};
+
+// Mixin declarations
+
+struct CompileDeclaration : AttribDeclaration
+{
+    Expression *exp;
+
+    ScopeDsymbol *sd;
+
+    CompileDeclaration(Loc loc, Expression *exp);
+    Dsymbol *syntaxCopy(Dsymbol *s);
+    int addMember(Scope *sc, ScopeDsymbol *sd, int memnum);
+    void semantic(Scope *sc);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+};
+
+#endif /* DMD_ATTRIB_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/cast.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,1419 @@
+
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <assert.h>
+
+#if _WIN32 || IN_GCC || IN_LLVM
+#include "mem.h"
+#else
+#include "../root/mem.h"
+#endif
+
+#include "expression.h"
+#include "mtype.h"
+#include "utf.h"
+#include "declaration.h"
+#include "aggregate.h"
+
+/* ==================== implicitCast ====================== */
+
+/**************************************
+ * Do an implicit cast.
+ * Issue error if it can't be done.
+ */
+
+Expression *Expression::implicitCastTo(Scope *sc, Type *t)
+{
+    //printf("implicitCastTo(%s) => %s\n", type->toChars(), t->toChars());
+    if (implicitConvTo(t))
+    {
+	if (global.params.warnings &&
+	    Type::impcnvWarn[type->toBasetype()->ty][t->toBasetype()->ty] &&
+	    op != TOKint64)
+	{
+	    Expression *e = optimize(WANTflags | WANTvalue);
+
+	    if (e->op == TOKint64)
+		return e->implicitCastTo(sc, t);
+
+	    fprintf(stdmsg, "warning - ");
+	    error("implicit conversion of expression (%s) of type %s to %s can cause loss of data",
+		toChars(), type->toChars(), t->toChars());
+	}
+	return castTo(sc, t);
+    }
+
+    Expression *e = optimize(WANTflags | WANTvalue);
+    if (e != this)
+	return e->implicitCastTo(sc, t);
+
+#if 0
+print();
+type->print();
+printf("to:\n");
+t->print();
+printf("%p %p type: %s to: %s\n", type->deco, t->deco, type->deco, t->deco);
+//printf("%p %p %p\n", type->next->arrayOf(), type, t);
+fflush(stdout);
+#endif
+    if (!t->deco)
+    {	/* Can happen with:
+	 *    enum E { One }
+	 *    class A
+	 *    { static void fork(EDG dg) { dg(E.One); }
+	 *	alias void delegate(E) EDG;
+	 *    }
+	 * Should eventually make it work.
+	 */
+	error("forward reference to type %s", t->toChars());
+    }
+    else if (t->reliesOnTident())
+	error("forward reference to type %s", t->reliesOnTident()->toChars());
+
+    error("cannot implicitly convert expression (%s) of type %s to %s",
+	toChars(), type->toChars(), t->toChars());
+    return castTo(sc, t);
+}
+
+/*******************************************
+ * Return !=0 if we can implicitly convert this to type t.
+ * Don't do the actual cast.
+ */
+
+MATCH Expression::implicitConvTo(Type *t)
+{
+#if 0
+    printf("Expression::implicitConvTo(this=%s, type=%s, t=%s)\n",
+	toChars(), type->toChars(), t->toChars());
+#endif
+    if (!type)
+    {	error("%s is not an expression", toChars());
+	type = Type::terror;
+    }
+    if (t->ty == Tbit && isBit())
+	return MATCHconvert;
+    Expression *e = optimize(WANTvalue | WANTflags);
+    if (e != this)
+    {	//printf("optimzed to %s\n", e->toChars());
+	return e->implicitConvTo(t);
+    }
+    MATCH match = type->implicitConvTo(t);
+    if (match)
+	return match;
+#if 0
+    Type *tb = t->toBasetype();
+    if (tb->ty == Tdelegate)
+    {	TypeDelegate *td = (TypeDelegate *)tb;
+	TypeFunction *tf = (TypeFunction *)td->next;
+
+	if (!tf->varargs &&
+	    !(tf->arguments && tf->arguments->dim)
+	   )
+	{
+	    match = type->implicitConvTo(tf->next);
+	    if (match)
+		return match;
+	    if (tf->next->toBasetype()->ty == Tvoid)
+		return MATCHconvert;
+	}
+    }
+#endif
+    return MATCHnomatch;
+}
+
+
+MATCH IntegerExp::implicitConvTo(Type *t)
+{
+#if 0
+    printf("IntegerExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
+	toChars(), type->toChars(), t->toChars());
+#endif
+    if (type->equals(t))
+	return MATCHexact;
+
+    enum TY ty = type->toBasetype()->ty;
+    enum TY toty = t->toBasetype()->ty;
+
+    if (type->implicitConvTo(t) == MATCHnomatch && t->ty == Tenum)
+    {
+	return MATCHnomatch;
+    }
+
+    switch (ty)
+    {
+	case Tbit:
+	case Tbool:
+	    value &= 1;
+	    ty = Tint32;
+	    break;
+
+	case Tint8:
+	    value = (signed char)value;
+	    ty = Tint32;
+	    break;
+
+	case Tchar:
+	case Tuns8:
+	    value &= 0xFF;
+	    ty = Tint32;
+	    break;
+
+	case Tint16:
+	    value = (short)value;
+	    ty = Tint32;
+	    break;
+
+	case Tuns16:
+	case Twchar:
+	    value &= 0xFFFF;
+	    ty = Tint32;
+	    break;
+
+	case Tint32:
+	    value = (int)value;
+	    break;
+
+	case Tuns32:
+	case Tdchar:
+	    value &= 0xFFFFFFFF;
+	    ty = Tuns32;
+	    break;
+
+	default:
+	    break;
+    }
+
+    // Only allow conversion if no change in value
+    switch (toty)
+    {
+	case Tbit:
+	case Tbool:
+	    if ((value & 1) != value)
+		goto Lno;
+	    goto Lyes;
+
+	case Tint8:
+	    if ((signed char)value != value)
+		goto Lno;
+	    goto Lyes;
+
+	case Tchar:
+	case Tuns8:
+	    //printf("value = %llu %llu\n", (integer_t)(unsigned char)value, value);
+	    if ((unsigned char)value != value)
+		goto Lno;
+	    goto Lyes;
+
+	case Tint16:
+	    if ((short)value != value)
+		goto Lno;
+	    goto Lyes;
+
+	case Tuns16:
+	    if ((unsigned short)value != value)
+		goto Lno;
+	    goto Lyes;
+
+	case Tint32:
+	    if (ty == Tuns32)
+	    {
+	    }
+	    else if ((int)value != value)
+		goto Lno;
+	    goto Lyes;
+
+	case Tuns32:
+	    if (ty == Tint32)
+	    {
+	    }
+	    else if ((unsigned)value != value)
+		goto Lno;
+	    goto Lyes;
+
+	case Tdchar:
+	    if (value > 0x10FFFFUL)
+		goto Lno;
+	    goto Lyes;
+
+	case Twchar:
+	    if ((unsigned short)value != value)
+		goto Lno;
+	    goto Lyes;
+
+	case Tfloat32:
+	{
+	    volatile float f;
+	    if (type->isunsigned())
+	    {
+		f = (float)value;
+		if (f != value)
+		    goto Lno;
+	    }
+	    else
+	    {
+		f = (float)(long long)value;
+		if (f != (long long)value)
+		    goto Lno;
+	    }
+	    goto Lyes;
+	}
+
+	case Tfloat64:
+	{
+	    volatile double f;
+	    if (type->isunsigned())
+	    {
+		f = (double)value;
+		if (f != value)
+		    goto Lno;
+	    }
+	    else
+	    {
+		f = (double)(long long)value;
+		if (f != (long long)value)
+		    goto Lno;
+	    }
+	    goto Lyes;
+	}
+
+	case Tfloat80:
+	{
+	    volatile long double f;
+	    if (type->isunsigned())
+	    {
+		f = (long double)value;
+		if (f != value)
+		    goto Lno;
+	    }
+	    else
+	    {
+		f = (long double)(long long)value;
+		if (f != (long long)value)
+		    goto Lno;
+	    }
+	    goto Lyes;
+	}
+    }
+    return Expression::implicitConvTo(t);
+
+Lyes:
+    //printf("MATCHconvert\n");
+    return MATCHconvert;
+
+Lno:
+    //printf("MATCHnomatch\n");
+    return MATCHnomatch;
+}
+
+MATCH NullExp::implicitConvTo(Type *t)
+{
+#if 0
+    printf("NullExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
+	toChars(), type->toChars(), t->toChars());
+#endif
+    if (this->type->equals(t))
+	return MATCHexact;
+    // NULL implicitly converts to any pointer type or dynamic array
+    if (type->ty == Tpointer && type->next->ty == Tvoid)
+    {
+	if (t->ty == Ttypedef)
+	    t = ((TypeTypedef *)t)->sym->basetype;
+	if (t->ty == Tpointer || t->ty == Tarray ||
+	    t->ty == Taarray  || t->ty == Tclass ||
+	    t->ty == Tdelegate)
+	    return committed ? MATCHconvert : MATCHexact;
+    }
+    return Expression::implicitConvTo(t);
+}
+
+MATCH StringExp::implicitConvTo(Type *t)
+{   MATCH m;
+
+#if 0
+    printf("StringExp::implicitConvTo(this=%s, committed=%d, type=%s, t=%s)\n",
+	toChars(), committed, type->toChars(), t->toChars());
+#endif
+    if (!committed)
+    {
+    if (!committed && t->ty == Tpointer && t->next->ty == Tvoid)
+    {
+	return MATCHnomatch;
+    }
+    if (type->ty == Tsarray || type->ty == Tarray || type->ty == Tpointer)
+    {
+	if (type->next->ty == Tchar)
+	{
+	    switch (t->ty)
+	    {
+		case Tsarray:
+		    if (type->ty == Tsarray &&
+			((TypeSArray *)type)->dim->toInteger() !=
+			((TypeSArray *)t)->dim->toInteger())
+			return MATCHnomatch;
+		    goto L1;
+		case Tarray:
+		    goto L1;
+		case Tpointer:
+		L1:
+		    if (t->next->ty == Tchar)
+			return MATCHexact;
+		    else if (t->next->ty == Twchar)
+			return MATCHexact;
+		    else if (t->next->ty == Tdchar)
+			return MATCHexact;
+		    break;
+	    }
+	}
+    }
+    }
+    return Expression::implicitConvTo(t);
+#if 0
+    m = (MATCH)type->implicitConvTo(t);
+    if (m)
+    {
+	return m;
+    }
+
+    return MATCHnomatch;
+#endif
+}
+
+MATCH ArrayLiteralExp::implicitConvTo(Type *t)
+{   MATCH result = MATCHexact;
+
+    Type *typeb = type->toBasetype();
+    Type *tb = t->toBasetype();
+    if ((tb->ty == Tarray || tb->ty == Tsarray) &&
+	(typeb->ty == Tarray || typeb->ty == Tsarray))
+    {
+	if (tb->ty == Tsarray)
+	{   TypeSArray *tsa = (TypeSArray *)tb;
+	    if (elements->dim != tsa->dim->toInteger())
+		result = MATCHnomatch;
+	}
+
+	for (int i = 0; i < elements->dim; i++)
+	{   Expression *e = (Expression *)elements->data[i];
+	    MATCH m = (MATCH)e->implicitConvTo(tb->next);
+	    if (m < result)
+		result = m;			// remember worst match
+	    if (result == MATCHnomatch)
+		break;				// no need to check for worse
+	}
+	return result;
+    }
+    else
+	return Expression::implicitConvTo(t);
+}
+
+MATCH AssocArrayLiteralExp::implicitConvTo(Type *t)
+{   MATCH result = MATCHexact;
+
+    Type *typeb = type->toBasetype();
+    Type *tb = t->toBasetype();
+    if (tb->ty == Taarray && typeb->ty == Taarray)
+    {
+	for (size_t i = 0; i < keys->dim; i++)
+	{   Expression *e = (Expression *)keys->data[i];
+	    MATCH m = (MATCH)e->implicitConvTo(((TypeAArray *)tb)->key);
+	    if (m < result)
+		result = m;			// remember worst match
+	    if (result == MATCHnomatch)
+		break;				// no need to check for worse
+	    e = (Expression *)values->data[i];
+	    m = (MATCH)e->implicitConvTo(tb->next);
+	    if (m < result)
+		result = m;			// remember worst match
+	    if (result == MATCHnomatch)
+		break;				// no need to check for worse
+	}
+	return result;
+    }
+    else
+	return Expression::implicitConvTo(t);
+}
+
+MATCH AddrExp::implicitConvTo(Type *t)
+{
+#if 0
+    printf("AddrExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
+	toChars(), type->toChars(), t->toChars());
+#endif
+    MATCH result;
+
+    result = type->implicitConvTo(t);
+    //printf("\tresult = %d\n", result);
+
+    if (result == MATCHnomatch)
+    {
+	// Look for pointers to functions where the functions are overloaded.
+	VarExp *ve;
+	FuncDeclaration *f;
+
+	t = t->toBasetype();
+	if (type->ty == Tpointer && type->next->ty == Tfunction &&
+	    t->ty == Tpointer && t->next->ty == Tfunction &&
+	    e1->op == TOKvar)
+	{
+	    ve = (VarExp *)e1;
+	    f = ve->var->isFuncDeclaration();
+	    if (f && f->overloadExactMatch(t->next))
+		result = MATCHexact;
+	}
+    }
+    //printf("\tresult = %d\n", result);
+    return result;
+}
+
+MATCH SymOffExp::implicitConvTo(Type *t)
+{
+#if 0
+    printf("SymOffExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
+	toChars(), type->toChars(), t->toChars());
+#endif
+    MATCH result;
+
+    result = type->implicitConvTo(t);
+    //printf("\tresult = %d\n", result);
+
+    if (result == MATCHnomatch)
+    {
+	// Look for pointers to functions where the functions are overloaded.
+	FuncDeclaration *f;
+
+	t = t->toBasetype();
+	if (type->ty == Tpointer && type->next->ty == Tfunction &&
+	    t->ty == Tpointer && t->next->ty == Tfunction)
+	{
+	    f = var->isFuncDeclaration();
+	    if (f && f->overloadExactMatch(t->next))
+		result = MATCHexact;
+	}
+    }
+    //printf("\tresult = %d\n", result);
+    return result;
+}
+
+MATCH DelegateExp::implicitConvTo(Type *t)
+{
+#if 0
+    printf("DelegateExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
+	toChars(), type->toChars(), t->toChars());
+#endif
+    MATCH result;
+
+    result = type->implicitConvTo(t);
+
+    if (result == 0)
+    {
+	// Look for pointers to functions where the functions are overloaded.
+	FuncDeclaration *f;
+
+	t = t->toBasetype();
+	if (type->ty == Tdelegate && type->next->ty == Tfunction &&
+	    t->ty == Tdelegate && t->next->ty == Tfunction)
+	{
+	    if (func && func->overloadExactMatch(t->next))
+		result = MATCHexact;
+	}
+    }
+    return result;
+}
+
+MATCH CondExp::implicitConvTo(Type *t)
+{
+    MATCH m1;
+    MATCH m2;
+
+    m1 = e1->implicitConvTo(t);
+    m2 = e2->implicitConvTo(t);
+
+    // Pick the worst match
+    return (m1 < m2) ? m1 : m2;
+}
+
+
+/* ==================== castTo ====================== */
+
+/**************************************
+ * Do an explicit cast.
+ */
+
+Expression *Expression::castTo(Scope *sc, Type *t)
+{   Expression *e;
+    Type *tb;
+
+    //printf("Expression::castTo(this=%s, t=%s)\n", toChars(), t->toChars());
+#if 0
+    printf("Expression::castTo(this=%s, type=%s, t=%s)\n",
+	toChars(), type->toChars(), t->toChars());
+#endif
+    e = this;
+    tb = t->toBasetype();
+    type = type->toBasetype();
+    if (tb != type)
+    {
+	if (tb->ty == Tbit && isBit())
+	    ;
+
+	// Do (type *) cast of (type [dim])
+	else if (tb->ty == Tpointer &&
+	    type->ty == Tsarray
+	   )
+	{
+	    //printf("Converting [dim] to *\n");
+
+	    if (type->size(loc) == 0)
+		e = new NullExp(loc);
+	    else
+		e = new AddrExp(loc, e);
+	}
+#if 0
+	else if (tb->ty == Tdelegate && type->ty != Tdelegate)
+	{
+	    TypeDelegate *td = (TypeDelegate *)tb;
+	    TypeFunction *tf = (TypeFunction *)td->next;
+	    return toDelegate(sc, tf->next);
+	}
+#endif
+	else
+	{
+	    e = new CastExp(loc, e, tb);
+	}
+    }
+    e->type = t;
+    //printf("Returning: %s\n", e->toChars());
+    return e;
+}
+
+
+Expression *RealExp::castTo(Scope *sc, Type *t)
+{
+    if (type->isreal() && t->isreal())
+	type = t;
+    else if (type->isimaginary() && t->isimaginary())
+	type = t;
+    else
+	return Expression::castTo(sc, t);
+    return this;
+}
+
+
+Expression *ComplexExp::castTo(Scope *sc, Type *t)
+{
+    if (type->iscomplex() && t->iscomplex())
+	type = t;
+    else
+	return Expression::castTo(sc, t);
+    return this;
+}
+
+
+Expression *NullExp::castTo(Scope *sc, Type *t)
+{   Expression *e;
+    Type *tb;
+
+    //printf("NullExp::castTo(t = %p)\n", t);
+    committed = 1;
+    e = this;
+    tb = t->toBasetype();
+    type = type->toBasetype();
+    if (tb != type)
+    {
+	// NULL implicitly converts to any pointer type or dynamic array
+	if (type->ty == Tpointer && type->next->ty == Tvoid &&
+	    (tb->ty == Tpointer || tb->ty == Tarray || tb->ty == Taarray ||
+	     tb->ty == Tdelegate))
+	{
+#if 0
+	    if (tb->ty == Tdelegate)
+	    {   TypeDelegate *td = (TypeDelegate *)tb;
+		TypeFunction *tf = (TypeFunction *)td->next;
+
+		if (!tf->varargs &&
+		    !(tf->arguments && tf->arguments->dim)
+		   )
+		{
+		    return Expression::castTo(sc, t);
+		}
+	    }
+#endif
+	}
+	else
+	{
+	    return Expression::castTo(sc, t);
+	    //e = new CastExp(loc, e, tb);
+	}
+    }
+    e->type = t;
+    return e;
+}
+
+Expression *StringExp::castTo(Scope *sc, Type *t)
+{
+    StringExp *se;
+    Type *tb;
+    int unique;
+
+    //printf("StringExp::castTo(t = %s), '%s' committed = %d\n", t->toChars(), toChars(), committed);
+
+    if (!committed && t->ty == Tpointer && t->next->ty == Tvoid)
+    {
+	error("cannot convert string literal to void*");
+    }
+
+    tb = t->toBasetype();
+    //printf("\ttype = %s\n", type->toChars());
+    if (tb->ty == Tdelegate && type->toBasetype()->ty != Tdelegate)
+	return Expression::castTo(sc, t);
+
+    se = this;
+    unique = 0;
+    if (!committed)
+    {
+	// Copy when committing the type
+	void *s;
+
+	s = (unsigned char *)mem.malloc((len + 1) * sz);
+	memcpy(s, string, (len + 1) * sz);
+	se = new StringExp(loc, s, len);
+	se->type = type;
+	se->sz = sz;
+	se->committed = 0;
+	unique = 1;		// this is the only instance
+    }
+    se->type = type->toBasetype();
+    if (tb == se->type)
+    {	se->type = t;
+	se->committed = 1;
+	return se;
+    }
+
+    if (tb->ty != Tsarray && tb->ty != Tarray && tb->ty != Tpointer)
+    {	se->committed = 1;
+	goto Lcast;
+    }
+    if (se->type->ty != Tsarray && se->type->ty != Tarray && se->type->ty != Tpointer)
+    {	se->committed = 1;
+	goto Lcast;
+    }
+
+    if (se->committed == 1)
+    {
+	if (se->type->next->size() == tb->next->size())
+	{   se->type = t;
+	    return se;
+	}
+	goto Lcast;
+    }
+
+    se->committed = 1;
+
+    int tfty;
+    int ttty;
+    char *p;
+    size_t u;
+    unsigned c;
+    size_t newlen;
+
+#define X(tf,tt)	((tf) * 256 + (tt))
+    {
+    OutBuffer buffer;
+    newlen = 0;
+    tfty = se->type->next->toBasetype()->ty;
+    ttty = tb->next->toBasetype()->ty;
+    switch (X(tfty, ttty))
+    {
+	case X(Tchar, Tchar):
+	case X(Twchar,Twchar):
+	case X(Tdchar,Tdchar):
+	    break;
+
+	case X(Tchar, Twchar):
+	    for (u = 0; u < len;)
+	    {
+		p = utf_decodeChar((unsigned char *)se->string, len, &u, &c);
+		if (p)
+		    error("%s", p);
+		else
+		    buffer.writeUTF16(c);
+	    }
+	    newlen = buffer.offset / 2;
+	    buffer.writeUTF16(0);
+	    goto L1;
+
+	case X(Tchar, Tdchar):
+	    for (u = 0; u < len;)
+	    {
+		p = utf_decodeChar((unsigned char *)se->string, len, &u, &c);
+		if (p)
+		    error("%s", p);
+		buffer.write4(c);
+		newlen++;
+	    }
+	    buffer.write4(0);
+	    goto L1;
+
+	case X(Twchar,Tchar):
+	    for (u = 0; u < len;)
+	    {
+		p = utf_decodeWchar((unsigned short *)se->string, len, &u, &c);
+		if (p)
+		    error("%s", p);
+		else
+		    buffer.writeUTF8(c);
+	    }
+	    newlen = buffer.offset;
+	    buffer.writeUTF8(0);
+	    goto L1;
+
+	case X(Twchar,Tdchar):
+	    for (u = 0; u < len;)
+	    {
+		p = utf_decodeWchar((unsigned short *)se->string, len, &u, &c);
+		if (p)
+		    error("%s", p);
+		buffer.write4(c);
+		newlen++;
+	    }
+	    buffer.write4(0);
+	    goto L1;
+
+	case X(Tdchar,Tchar):
+	    for (u = 0; u < len; u++)
+	    {
+		c = ((unsigned *)se->string)[u];
+		if (!utf_isValidDchar(c))
+		    error("invalid UCS-32 char \\U%08x", c);
+		else
+		    buffer.writeUTF8(c);
+		newlen++;
+	    }
+	    newlen = buffer.offset;
+	    buffer.writeUTF8(0);
+	    goto L1;
+
+	case X(Tdchar,Twchar):
+	    for (u = 0; u < len; u++)
+	    {
+		c = ((unsigned *)se->string)[u];
+		if (!utf_isValidDchar(c))
+		    error("invalid UCS-32 char \\U%08x", c);
+		else
+		    buffer.writeUTF16(c);
+		newlen++;
+	    }
+	    newlen = buffer.offset / 2;
+	    buffer.writeUTF16(0);
+	    goto L1;
+
+	L1:
+	    if (!unique)
+		se = new StringExp(loc, NULL, 0);
+	    se->string = buffer.extractData();
+	    se->len = newlen;
+	    se->sz = tb->next->size();
+	    break;
+
+	default:
+	    if (se->type->next->size() == tb->next->size())
+	    {	se->type = t;
+		return se;
+	    }
+	    goto Lcast;
+    }
+    }
+#undef X
+
+    // See if need to truncate or extend the literal
+    if (tb->ty == Tsarray)
+    {
+	int dim2 = ((TypeSArray *)tb)->dim->toInteger();
+
+	//printf("dim from = %d, to = %d\n", se->len, dim2);
+
+	// Changing dimensions
+	if (dim2 != se->len)
+	{
+	    unsigned newsz = se->sz;
+
+	    if (unique && dim2 < se->len)
+	    {   se->len = dim2;
+		// Add terminating 0
+		memset((unsigned char *)se->string + dim2 * newsz, 0, newsz);
+	    }
+	    else
+	    {
+		// Copy when changing the string literal
+		void *s;
+		int d;
+
+		d = (dim2 < se->len) ? dim2 : se->len;
+		s = (unsigned char *)mem.malloc((dim2 + 1) * newsz);
+		memcpy(s, se->string, d * newsz);
+		// Extend with 0, add terminating 0
+		memset((char *)s + d * newsz, 0, (dim2 + 1 - d) * newsz);
+		se = new StringExp(loc, s, dim2);
+		se->committed = 1;	// it now has a firm type
+		se->sz = newsz;
+	    }
+	}
+    }
+    se->type = t;
+    return se;
+
+Lcast:
+    Expression *e = new CastExp(loc, se, t);
+    e->type = t;
+    return e;
+}
+
+Expression *AddrExp::castTo(Scope *sc, Type *t)
+{
+    Type *tb;
+
+#if 0
+    printf("AddrExp::castTo(this=%s, type=%s, t=%s)\n",
+	toChars(), type->toChars(), t->toChars());
+#endif
+    Expression *e = this;
+
+    tb = t->toBasetype();
+    type = type->toBasetype();
+    if (tb != type)
+    {
+	// Look for pointers to functions where the functions are overloaded.
+	VarExp *ve;
+	FuncDeclaration *f;
+
+	if (type->ty == Tpointer && type->next->ty == Tfunction &&
+	    tb->ty == Tpointer && tb->next->ty == Tfunction &&
+	    e1->op == TOKvar)
+	{
+	    ve = (VarExp *)e1;
+	    f = ve->var->isFuncDeclaration();
+	    if (f)
+	    {
+		f = f->overloadExactMatch(tb->next);
+		if (f)
+		{
+		    e = new VarExp(loc, f);
+		    e->type = f->type;
+		    e = new AddrExp(loc, e);
+		    e->type = t;
+		    return e;
+		}
+	    }
+	}
+	e = Expression::castTo(sc, t);
+    }
+    e->type = t;
+    return e;
+}
+
+
+Expression *TupleExp::castTo(Scope *sc, Type *t)
+{
+    for (size_t i = 0; i < exps->dim; i++)
+    {   Expression *e = (Expression *)exps->data[i];
+	e = e->castTo(sc, t);
+	exps->data[i] = (void *)e;
+    }
+    return this;
+}
+
+
+Expression *ArrayLiteralExp::castTo(Scope *sc, Type *t)
+{
+    Type *typeb = type->toBasetype();
+    Type *tb = t->toBasetype();
+    if ((tb->ty == Tarray || tb->ty == Tsarray) &&
+	(typeb->ty == Tarray || typeb->ty == Tsarray) &&
+	tb->next->toBasetype()->ty != Tvoid)
+    {
+	if (tb->ty == Tsarray)
+	{   TypeSArray *tsa = (TypeSArray *)tb;
+	    if (elements->dim != tsa->dim->toInteger())
+		goto L1;
+	}
+
+	for (int i = 0; i < elements->dim; i++)
+	{   Expression *e = (Expression *)elements->data[i];
+	    e = e->castTo(sc, tb->next);
+	    elements->data[i] = (void *)e;
+	}
+	type = t;
+	return this;
+    }
+    if (tb->ty == Tpointer && typeb->ty == Tsarray)
+    {
+	type = typeb->next->pointerTo();
+    }
+L1:
+    return Expression::castTo(sc, t);
+}
+
+Expression *AssocArrayLiteralExp::castTo(Scope *sc, Type *t)
+{
+    Type *typeb = type->toBasetype();
+    Type *tb = t->toBasetype();
+    if (tb->ty == Taarray && typeb->ty == Taarray &&
+	tb->next->toBasetype()->ty != Tvoid)
+    {
+	assert(keys->dim == values->dim);
+	for (size_t i = 0; i < keys->dim; i++)
+	{   Expression *e = (Expression *)values->data[i];
+	    e = e->castTo(sc, tb->next);
+	    values->data[i] = (void *)e;
+
+	    e = (Expression *)keys->data[i];
+	    e = e->castTo(sc, ((TypeAArray *)tb)->key);
+	    keys->data[i] = (void *)e;
+	}
+	type = t;
+	return this;
+    }
+L1:
+    return Expression::castTo(sc, t);
+}
+
+Expression *SymOffExp::castTo(Scope *sc, Type *t)
+{
+    Type *tb;
+
+#if 0
+    printf("SymOffExp::castTo(this=%s, type=%s, t=%s)\n",
+	toChars(), type->toChars(), t->toChars());
+#endif
+    Expression *e = this;
+
+    tb = t->toBasetype();
+    type = type->toBasetype();
+    if (tb != type)
+    {
+	// Look for pointers to functions where the functions are overloaded.
+	FuncDeclaration *f;
+
+	if (type->ty == Tpointer && type->next->ty == Tfunction &&
+	    tb->ty == Tpointer && tb->next->ty == Tfunction)
+	{
+	    f = var->isFuncDeclaration();
+	    if (f)
+	    {
+		f = f->overloadExactMatch(tb->next);
+		if (f)
+		{
+		    e = new SymOffExp(loc, f, 0);
+		    e->type = t;
+		    return e;
+		}
+	    }
+	}
+	e = Expression::castTo(sc, t);
+    }
+    e->type = t;
+    return e;
+}
+
+Expression *DelegateExp::castTo(Scope *sc, Type *t)
+{
+    Type *tb;
+#if 0
+    printf("DelegateExp::castTo(this=%s, type=%s, t=%s)\n",
+	toChars(), type->toChars(), t->toChars());
+#endif
+    Expression *e = this;
+    static char msg[] = "cannot form delegate due to covariant return type";
+
+    tb = t->toBasetype();
+    type = type->toBasetype();
+    if (tb != type)
+    {
+	// Look for delegates to functions where the functions are overloaded.
+	FuncDeclaration *f;
+
+	if (type->ty == Tdelegate && type->next->ty == Tfunction &&
+	    tb->ty == Tdelegate && tb->next->ty == Tfunction)
+	{
+	    if (func)
+	    {
+		f = func->overloadExactMatch(tb->next);
+		if (f)
+		{   int offset;
+		    if (f->tintro && f->tintro->next->isBaseOf(f->type->next, &offset) && offset)
+			error("%s", msg);
+		    e = new DelegateExp(loc, e1, f);
+		    e->type = t;
+		    return e;
+		}
+		if (func->tintro)
+		    error("%s", msg);
+	    }
+	}
+	e = Expression::castTo(sc, t);
+    }
+    else
+    {	int offset;
+
+	if (func->tintro && func->tintro->next->isBaseOf(func->type->next, &offset) && offset)
+	    error("%s", msg);
+    }
+    e->type = t;
+    return e;
+}
+
+Expression *CondExp::castTo(Scope *sc, Type *t)
+{
+    Expression *e = this;
+
+    if (type != t)
+    {
+	if (1 || e1->op == TOKstring || e2->op == TOKstring)
+	{   e = new CondExp(loc, econd, e1->castTo(sc, t), e2->castTo(sc, t));
+	    e->type = t;
+	}
+	else
+	    e = Expression::castTo(sc, t);
+    }
+    return e;
+}
+
+/* ==================== ====================== */
+
+/****************************************
+ * Scale addition/subtraction to/from pointer.
+ */
+
+Expression *BinExp::scaleFactor(Scope *sc)
+{   d_uns64 stride;
+    Type *t1b = e1->type->toBasetype();
+    Type *t2b = e2->type->toBasetype();
+
+    if (t1b->ty == Tpointer && t2b->isintegral())
+    {   // Need to adjust operator by the stride
+	// Replace (ptr + int) with (ptr + (int * stride))
+	Type *t = Type::tptrdiff_t;
+
+	stride = t1b->next->size();
+	if (!t->equals(t2b))
+	    e2 = e2->castTo(sc, t);
+    // LLVMDC: llvm uses typesafe pointer arithmetic
+    #if !IN_LLVM
+	if (t1b->next->isbit())
+	    // BUG: should add runtime check for misaligned offsets
+	    // This perhaps should be done by rewriting as &p[i]
+	    // and letting back end do it.
+	    e2 = new UshrExp(loc, e2, new IntegerExp(0, 3, t));
+	else
+	    e2 = new MulExp(loc, e2, new IntegerExp(0, stride, t));
+    #endif
+	e2->type = t;
+	type = e1->type;
+    }
+    else if (t2b->ty && t1b->isintegral())
+    {   // Need to adjust operator by the stride
+	// Replace (int + ptr) with (ptr + (int * stride))
+	Type *t = Type::tptrdiff_t;
+	Expression *e;
+
+	stride = t2b->next->size();
+	if (!t->equals(t1b))
+	    e = e1->castTo(sc, t);
+	else
+	    e = e1;
+	if (t2b->next->isbit())
+	    // BUG: should add runtime check for misaligned offsets
+	    e = new UshrExp(loc, e, new IntegerExp(0, 3, t));
+	else
+	    e = new MulExp(loc, e, new IntegerExp(0, stride, t));
+	e->type = t;
+	type = e2->type;
+	e1 = e2;
+	e2 = e;
+    }
+    return this;
+}
+
+/************************************
+ * Bring leaves to common type.
+ */
+
+Expression *BinExp::typeCombine(Scope *sc)
+{
+    Type *t1;
+    Type *t2;
+    Type *t;
+    TY ty;
+
+    //printf("BinExp::typeCombine()\n");
+    //dump(0);
+
+    e1 = e1->integralPromotions(sc);
+    e2 = e2->integralPromotions(sc);
+
+    // BUG: do toBasetype()
+    t1 = e1->type;
+    t2 = e2->type;
+    assert(t1);
+
+    //if (t1) printf("\tt1 = %s\n", t1->toChars());
+    //if (t2) printf("\tt2 = %s\n", t2->toChars());
+#ifdef DEBUG
+    if (!t2) printf("\te2 = '%s'\n", e2->toChars());
+#endif
+    assert(t2);
+
+    Type *t1b = t1->toBasetype();
+    Type *t2b = t2->toBasetype();
+
+    ty = (TY)Type::impcnvResult[t1b->ty][t2b->ty];
+    if (ty != Terror)
+    {	TY ty1;
+	TY ty2;
+
+	ty1 = (TY)Type::impcnvType1[t1b->ty][t2b->ty];
+	ty2 = (TY)Type::impcnvType2[t1b->ty][t2b->ty];
+
+	if (t1b->ty == ty1)	// if no promotions
+	{
+	    if (t1 == t2)
+	    {
+		if (!type)
+		    type = t1;
+		return this;
+	    }
+
+	    if (t1b == t2b)
+	    {
+		if (!type)
+		    type = t1b;
+		return this;
+	    }
+	}
+
+	if (!type)
+	    type = Type::basic[ty];
+
+	t1 = Type::basic[ty1];
+	t2 = Type::basic[ty2];
+	e1 = e1->castTo(sc, t1);
+	e2 = e2->castTo(sc, t2);
+#if 0
+	if (type != Type::basic[ty])
+	{   t = type;
+	    type = Type::basic[ty];
+	    return castTo(sc, t);
+	}
+#endif
+	//printf("after typeCombine():\n");
+	//dump(0);
+	//printf("ty = %d, ty1 = %d, ty2 = %d\n", ty, ty1, ty2);
+	return this;
+    }
+
+    t = t1;
+    if (t1 == t2)
+    {
+	if ((t1->ty == Tstruct || t1->ty == Tclass) &&
+	    (op == TOKmin || op == TOKadd))
+	    goto Lincompatible;
+    }
+    else if (t1->isintegral() && t2->isintegral())
+    {
+	printf("t1 = %s, t2 = %s\n", t1->toChars(), t2->toChars());
+	int sz1 = t1->size();
+	int sz2 = t2->size();
+	int sign1 = t1->isunsigned() == 0;
+	int sign2 = t2->isunsigned() == 0;
+
+	if (sign1 == sign2)
+	{
+	    if (sz1 < sz2)
+		goto Lt2;
+	    else
+		goto Lt1;
+	}
+	if (!sign1)
+	{
+	    if (sz1 >= sz2)
+		goto Lt1;
+	    else
+		goto Lt2;
+	}
+	else
+	{
+	    if (sz2 >= sz1)
+		goto Lt2;
+	    else
+		goto Lt1;
+	}
+    }
+    else if (t1->ty == Tpointer && t2->ty == Tpointer)
+    {
+	// Bring pointers to compatible type
+	Type *t1n = t1->next;
+	Type *t2n = t2->next;
+
+//t1->print();
+//t2->print();
+//if (t1n == t2n) *(char *)0 = 0;
+	assert(t1n != t2n);
+	if (t1n->ty == Tvoid)		// pointers to void are always compatible
+	    t = t2;
+	else if (t2n->ty == Tvoid)
+	    ;
+	else if (t1n->ty == Tclass && t2n->ty == Tclass)
+	{   ClassDeclaration *cd1 = t1n->isClassHandle();
+	    ClassDeclaration *cd2 = t2n->isClassHandle();
+	    int offset;
+
+	    if (cd1->isBaseOf(cd2, &offset))
+	    {
+		if (offset)
+		    e2 = e2->castTo(sc, t);
+	    }
+	    else if (cd2->isBaseOf(cd1, &offset))
+	    {
+		t = t2;
+		if (offset)
+		    e1 = e1->castTo(sc, t);
+	    }
+	    else
+		goto Lincompatible;
+	}
+	else
+	    goto Lincompatible;
+    }
+    else if ((t1->ty == Tsarray || t1->ty == Tarray) &&
+	     e2->op == TOKnull && t2->ty == Tpointer && t2->next->ty == Tvoid)
+    {
+	goto Lx1;
+    }
+    else if ((t2->ty == Tsarray || t2->ty == Tarray) &&
+	     e1->op == TOKnull && t1->ty == Tpointer && t1->next->ty == Tvoid)
+    {
+	goto Lx2;
+    }
+    else if ((t1->ty == Tsarray || t1->ty == Tarray) && t1->implicitConvTo(t2))
+    {
+	goto Lt2;
+    }
+    else if ((t2->ty == Tsarray || t2->ty == Tarray) && t2->implicitConvTo(t1))
+    {
+	goto Lt1;
+    }
+    else if (t1->ty == Tclass || t2->ty == Tclass)
+    {	int i1;
+	int i2;
+
+	i1 = e2->implicitConvTo(t1);
+	i2 = e1->implicitConvTo(t2);
+
+	if (i1 && i2)
+	{
+	    // We have the case of class vs. void*, so pick class
+	    if (t1->ty == Tpointer)
+		i1 = 0;
+	    else if (t2->ty == Tpointer)
+		i2 = 0;
+	}
+
+	if (i2)
+	{
+	    goto Lt2;
+	}
+	else if (i1)
+	{
+	    goto Lt1;
+	}
+	else
+	    goto Lincompatible;
+    }
+    else if ((e1->op == TOKstring || e1->op == TOKnull) && e1->implicitConvTo(t2))
+    {
+	goto Lt2;
+    }
+//else if (e2->op == TOKstring) { printf("test2\n"); }
+    else if ((e2->op == TOKstring || e2->op == TOKnull) && e2->implicitConvTo(t1))
+    {
+	goto Lt1;
+    }
+    else if (t1->ty == Tsarray && t2->ty == Tsarray &&
+	     e2->implicitConvTo(t1->next->arrayOf()))
+    {
+     Lx1:
+	t = t1->next->arrayOf();
+	e1 = e1->castTo(sc, t);
+	e2 = e2->castTo(sc, t);
+    }
+    else if (t1->ty == Tsarray && t2->ty == Tsarray &&
+	     e1->implicitConvTo(t2->next->arrayOf()))
+    {
+     Lx2:
+	t = t2->next->arrayOf();
+	e1 = e1->castTo(sc, t);
+	e2 = e2->castTo(sc, t);
+    }
+    else
+    {
+     Lincompatible:
+	incompatibleTypes();
+    }
+Lret:
+    if (!type)
+	type = t;
+    //dump(0);
+    return this;
+
+
+Lt1:
+    e2 = e2->castTo(sc, t1);
+    t = t1;
+    goto Lret;
+
+Lt2:
+    e1 = e1->castTo(sc, t2);
+    t = t2;
+    goto Lret;
+}
+
+/***********************************
+ * Do integral promotions (convertchk).
+ * Don't convert <array of> to <pointer to>
+ */
+
+Expression *Expression::integralPromotions(Scope *sc)
+{   Expression *e;
+
+    e = this;
+    switch (type->toBasetype()->ty)
+    {
+	case Tvoid:
+	    error("void has no value");
+	    break;
+
+	case Tint8:
+	case Tuns8:
+	case Tint16:
+	case Tuns16:
+	case Tbit:
+	case Tbool:
+	case Tchar:
+	case Twchar:
+	    e = e->castTo(sc, Type::tint32);
+	    break;
+
+	case Tdchar:
+	    e = e->castTo(sc, Type::tuns32);
+	    break;
+    }
+    return e;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/class.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,1267 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "root.h"
+#include "mem.h"
+
+#include "enum.h"
+#include "init.h"
+#include "attrib.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "id.h"
+#include "mtype.h"
+#include "scope.h"
+#include "module.h"
+#include "expression.h"
+#include "statement.h"
+
+/********************************* ClassDeclaration ****************************/
+
+ClassDeclaration *ClassDeclaration::classinfo;
+ClassDeclaration *ClassDeclaration::object;
+
+ClassDeclaration::ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses)
+    : AggregateDeclaration(loc, id)
+{
+    static char msg[] = "only object.d can define this reserved class name";
+
+    if (baseclasses)
+	this->baseclasses = *baseclasses;
+    baseClass = NULL;
+
+    interfaces_dim = 0;
+    interfaces = NULL;
+
+    vtblInterfaces = NULL;
+
+    //printf("ClassDeclaration(%s), dim = %d\n", id->toChars(), this->baseclasses.dim);
+
+    // For forward references
+    type = new TypeClass(this);
+    handle = type;
+
+    ctor = NULL;
+    defaultCtor = NULL;
+    staticCtor = NULL;
+    staticDtor = NULL;
+
+    vtblsym = NULL;
+    vclassinfo = NULL;
+
+    if (id)
+    {	// Look for special class names
+
+	if (id == Id::__sizeof || id == Id::alignof || id == Id::mangleof)
+	    error("illegal class name");
+
+	// BUG: What if this is the wrong TypeInfo, i.e. it is nested?
+	if (id->toChars()[0] == 'T')
+	{
+	    if (id == Id::TypeInfo)
+	    {	if (Type::typeinfo)
+		    Type::typeinfo->error("%s", msg);
+		Type::typeinfo = this;
+	    }
+
+	    if (id == Id::TypeInfo_Class)
+	    {	if (Type::typeinfoclass)
+		    Type::typeinfoclass->error("%s", msg);
+		Type::typeinfoclass = this;
+	    }
+
+	    if (id == Id::TypeInfo_Interface)
+	    {	if (Type::typeinfointerface)
+		    Type::typeinfointerface->error("%s", msg);
+		Type::typeinfointerface = this;
+	    }
+
+	    if (id == Id::TypeInfo_Struct)
+	    {	if (Type::typeinfostruct)
+		    Type::typeinfostruct->error("%s", msg);
+		Type::typeinfostruct = this;
+	    }
+
+	    if (id == Id::TypeInfo_Typedef)
+	    {	if (Type::typeinfotypedef)
+		    Type::typeinfotypedef->error("%s", msg);
+		Type::typeinfotypedef = this;
+	    }
+
+	    if (id == Id::TypeInfo_Pointer)
+	    {	if (Type::typeinfopointer)
+		    Type::typeinfopointer->error("%s", msg);
+		Type::typeinfopointer = this;
+	    }
+
+	    if (id == Id::TypeInfo_Array)
+	    {	if (Type::typeinfoarray)
+		    Type::typeinfoarray->error("%s", msg);
+		Type::typeinfoarray = this;
+	    }
+
+	    if (id == Id::TypeInfo_StaticArray)
+	    {	//if (Type::typeinfostaticarray)
+		    //Type::typeinfostaticarray->error("%s", msg);
+		Type::typeinfostaticarray = this;
+	    }
+
+	    if (id == Id::TypeInfo_AssociativeArray)
+	    {	if (Type::typeinfoassociativearray)
+		    Type::typeinfoassociativearray->error("%s", msg);
+		Type::typeinfoassociativearray = this;
+	    }
+
+	    if (id == Id::TypeInfo_Enum)
+	    {	if (Type::typeinfoenum)
+		    Type::typeinfoenum->error("%s", msg);
+		Type::typeinfoenum = this;
+	    }
+
+	    if (id == Id::TypeInfo_Function)
+	    {	if (Type::typeinfofunction)
+		    Type::typeinfofunction->error("%s", msg);
+		Type::typeinfofunction = this;
+	    }
+
+	    if (id == Id::TypeInfo_Delegate)
+	    {	if (Type::typeinfodelegate)
+		    Type::typeinfodelegate->error("%s", msg);
+		Type::typeinfodelegate = this;
+	    }
+
+	    if (id == Id::TypeInfo_Tuple)
+	    {	if (Type::typeinfotypelist)
+		    Type::typeinfotypelist->error("%s", msg);
+		Type::typeinfotypelist = this;
+	    }
+	}
+
+	if (id == Id::Object)
+	{   if (object)
+		object->error("%s", msg);
+	    object = this;
+	}
+
+	if (id == Id::ClassInfo)
+	{   if (classinfo)
+		classinfo->error("%s", msg);
+	    classinfo = this;
+	}
+
+	if (id == Id::ModuleInfo)
+	{   if (Module::moduleinfo)
+		Module::moduleinfo->error("%s", msg);
+	    Module::moduleinfo = this;
+	}
+    }
+
+    com = 0;
+#if 0
+    if (id == Id::IUnknown)		// IUnknown is the root of all COM objects
+	com = 1;
+#endif
+    isauto = 0;
+    isabstract = 0;
+    isnested = 0;
+    vthis = NULL;
+}
+
+Dsymbol *ClassDeclaration::syntaxCopy(Dsymbol *s)
+{
+    ClassDeclaration *cd;
+
+    //printf("ClassDeclaration::syntaxCopy('%s')\n", toChars());
+    if (s)
+	cd = (ClassDeclaration *)s;
+    else
+	cd = new ClassDeclaration(loc, ident, NULL);
+
+    cd->storage_class |= storage_class;
+
+    cd->baseclasses.setDim(this->baseclasses.dim);
+    for (int i = 0; i < cd->baseclasses.dim; i++)
+    {
+	BaseClass *b = (BaseClass *)this->baseclasses.data[i];
+	BaseClass *b2 = new BaseClass(b->type->syntaxCopy(), b->protection);
+	cd->baseclasses.data[i] = b2;
+    }
+
+    ScopeDsymbol::syntaxCopy(cd);
+    return cd;
+}
+
+void ClassDeclaration::semantic(Scope *sc)
+{   int i;
+    unsigned offset;
+
+    //printf("ClassDeclaration::semantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this);
+    //printf("\tparent = %p, '%s'\n", sc->parent, sc->parent ? sc->parent->toChars() : "");
+    //printf("sc->stc = %x\n", sc->stc);
+
+    //{ static int n;  if (++n == 20) *(char*)0=0; }
+
+    if (!ident)		// if anonymous class
+    {	char *id = "__anonclass";
+
+	ident = Identifier::generateId(id);
+    }
+
+    if (!scope)
+    {
+	if (!parent && sc->parent && !sc->parent->isModule())
+	    parent = sc->parent;
+
+	type = type->semantic(loc, sc);
+	handle = handle->semantic(loc, sc);
+    }
+    if (!members)			// if forward reference
+    {	//printf("\tclass '%s' is forward referenced\n", toChars());
+	return;
+    }
+    if (symtab)
+    {	if (!scope)
+	{   //printf("\tsemantic for '%s' is already completed\n", toChars());
+	    return;		// semantic() already completed
+	}
+    }
+    else
+	symtab = new DsymbolTable();
+
+    Scope *scx = NULL;
+    if (scope)
+    {	sc = scope;
+	scx = scope;		// save so we don't make redundant copies
+	scope = NULL;
+    }
+#ifdef IN_GCC
+    methods.setDim(0);
+#endif
+
+    // Expand any tuples in baseclasses[]
+    for (i = 0; i < baseclasses.dim; )
+    {	BaseClass *b = (BaseClass *)baseclasses.data[i];
+	b->type = b->type->semantic(loc, sc);
+	Type *tb = b->type->toBasetype();
+
+	if (tb->ty == Ttuple)
+	{   TypeTuple *tup = (TypeTuple *)tb;
+	    enum PROT protection = b->protection;
+	    baseclasses.remove(i);
+	    size_t dim = Argument::dim(tup->arguments);
+	    for (size_t j = 0; j < dim; j++)
+	    {	Argument *arg = Argument::getNth(tup->arguments, j);
+		b = new BaseClass(arg->type, protection);
+		baseclasses.insert(i + j, b);
+	    }
+	}
+	else
+	    i++;
+    }
+
+    // See if there's a base class as first in baseclasses[]
+    if (baseclasses.dim)
+    {	TypeClass *tc;
+	BaseClass *b;
+	Type *tb;
+
+	b = (BaseClass *)baseclasses.data[0];
+	//b->type = b->type->semantic(loc, sc);
+	tb = b->type->toBasetype();
+	if (tb->ty != Tclass)
+	{   error("base type must be class or interface, not %s", b->type->toChars());
+	    baseclasses.remove(0);
+	}
+	else
+	{
+	    tc = (TypeClass *)(tb);
+	    if (tc->sym->isInterfaceDeclaration())
+		;
+	    else
+	    {
+		for (ClassDeclaration *cdb = tc->sym; cdb; cdb = cdb->baseClass)
+		{
+		    if (cdb == this)
+		    {
+			error("circular inheritance");
+			baseclasses.remove(0);
+			goto L7;
+		    }
+		}
+		if (!tc->sym->symtab || tc->sym->scope || tc->sym->sizeok == 0)
+		{
+		    //error("forward reference of base class %s", baseClass->toChars());
+		    // Forward reference of base class, try again later
+		    //printf("\ttry later, forward reference of base class %s\n", tc->sym->toChars());
+		    scope = scx ? scx : new Scope(*sc);
+		    scope->setNoFree();
+		    scope->module->addDeferredSemantic(this);
+		    return;
+		}
+		else
+		{   baseClass = tc->sym;
+		    b->base = baseClass;
+		}
+	     L7: ;
+	    }
+	}
+    }
+
+    // Treat the remaining entries in baseclasses as interfaces
+    // Check for errors, handle forward references
+    for (i = (baseClass ? 1 : 0); i < baseclasses.dim; )
+    {	TypeClass *tc;
+	BaseClass *b;
+	Type *tb;
+
+	b = (BaseClass *)baseclasses.data[i];
+	b->type = b->type->semantic(loc, sc);
+	tb = b->type->toBasetype();
+	if (tb->ty == Tclass)
+	    tc = (TypeClass *)tb;
+	else
+	    tc = NULL;
+	if (!tc || !tc->sym->isInterfaceDeclaration())
+	{
+	    error("base type must be interface, not %s", b->type->toChars());
+	    baseclasses.remove(i);
+	    continue;
+	}
+	else
+	{
+	    // Check for duplicate interfaces
+	    for (size_t j = (baseClass ? 1 : 0); j < i; j++)
+	    {
+		BaseClass *b2 = (BaseClass *)baseclasses.data[j];
+		if (b2->base == tc->sym)
+		    error("inherits from duplicate interface %s", b2->base->toChars());
+	    }
+
+	    b->base = tc->sym;
+	    if (!b->base->symtab || b->base->scope)
+	    {
+		//error("forward reference of base class %s", baseClass->toChars());
+		// Forward reference of base, try again later
+		//printf("\ttry later, forward reference of base %s\n", baseClass->toChars());
+		scope = scx ? scx : new Scope(*sc);
+		scope->setNoFree();
+		scope->module->addDeferredSemantic(this);
+		return;
+	    }
+	}
+	i++;
+    }
+
+
+    // If no base class, and this is not an Object, use Object as base class
+    if (!baseClass && ident != Id::Object)
+    {
+	// BUG: what if Object is redefined in an inner scope?
+	Type *tbase = new TypeIdentifier(0, Id::Object);
+	BaseClass *b;
+	TypeClass *tc;
+	Type *bt;
+
+	if (!object)
+	{
+	    error("missing or corrupt object.d");
+	    fatal();
+	}
+	bt = tbase->semantic(loc, sc)->toBasetype();
+	b = new BaseClass(bt, PROTpublic);
+	baseclasses.shift(b);
+	assert(b->type->ty == Tclass);
+	tc = (TypeClass *)(b->type);
+	baseClass = tc->sym;
+	assert(!baseClass->isInterfaceDeclaration());
+	b->base = baseClass;
+    }
+
+    interfaces_dim = baseclasses.dim;
+    interfaces = (BaseClass **)baseclasses.data;
+
+
+    if (baseClass)
+    {
+	if (baseClass->storage_class & STCfinal)
+	    error("cannot inherit from final class %s", baseClass->toChars());
+
+	interfaces_dim--;
+	interfaces++;
+
+	// Copy vtbl[] from base class
+	vtbl.setDim(baseClass->vtbl.dim);
+	memcpy(vtbl.data, baseClass->vtbl.data, sizeof(void *) * vtbl.dim);
+
+	// Inherit properties from base class
+	com = baseClass->isCOMclass();
+	isauto = baseClass->isauto;
+	vthis = baseClass->vthis;
+    }
+    else
+    {
+	// No base class, so this is the root of the class hierarchy
+	vtbl.setDim(0);
+	vtbl.push(this);		// leave room for classinfo as first member
+    }
+
+    protection = sc->protection;
+    storage_class |= sc->stc;
+
+    if (sizeok == 0)
+    {
+	interfaceSemantic(sc);
+
+	for (i = 0; i < members->dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)members->data[i];
+	    s->addMember(sc, this, 1);
+	}
+
+	/* If this is a nested class, add the hidden 'this'
+	 * member which is a pointer to the enclosing scope.
+	 */
+	if (vthis)		// if inheriting from nested class
+	{   // Use the base class's 'this' member
+	    isnested = 1;
+	    if (storage_class & STCstatic)
+		error("static class cannot inherit from nested class %s", baseClass->toChars());
+	    if (toParent2() != baseClass->toParent2())
+		error("super class %s is nested within %s, not %s",
+			baseClass->toChars(),
+			baseClass->toParent2()->toChars(),
+			toParent2()->toChars());
+	}
+	else if (!(storage_class & STCstatic))
+	{   Dsymbol *s = toParent2();
+	    if (s)
+	    {
+		ClassDeclaration *cd = s->isClassDeclaration();
+		FuncDeclaration *fd = s->isFuncDeclaration();
+
+
+		if (cd || fd)
+		{   isnested = 1;
+		    Type *t;
+		    if (cd)
+			t = cd->type;
+		    else if (fd)
+		    {	AggregateDeclaration *ad = fd->isMember2();
+			if (ad)
+			    t = ad->handle;
+			else
+			{
+			    t = new TypePointer(Type::tvoid);
+			    t = t->semantic(0, sc);
+			}
+		    }
+		    else
+			assert(0);
+		    assert(!vthis);
+		    vthis = new ThisDeclaration(t);
+		    members->push(vthis);
+		}
+	    }
+	}
+    }
+
+    if (storage_class & (STCauto | STCscope))
+	isauto = 1;
+    if (storage_class & STCabstract)
+	isabstract = 1;
+    if (storage_class & STCdeprecated)
+	isdeprecated = 1;
+
+    sc = sc->push(this);
+    sc->stc &= ~(STCfinal | STCauto | STCscope | STCstatic |
+		 STCabstract | STCdeprecated);
+    sc->parent = this;
+    sc->inunion = 0;
+
+    if (isCOMclass())
+	sc->linkage = LINKwindows;
+    sc->protection = PROTpublic;
+    sc->explicitProtection = 0;
+    sc->structalign = 8;
+    structalign = sc->structalign;
+    if (baseClass)
+    {	sc->offset = baseClass->structsize;
+	alignsize = baseClass->alignsize;
+//	if (isnested)
+//	    sc->offset += PTRSIZE;	// room for uplevel context pointer
+    }
+    else
+    {	sc->offset = 8;		// allow room for vptr[] and monitor
+	alignsize = 4;
+    }
+    structsize = sc->offset;
+    Scope scsave = *sc;
+    int members_dim = members->dim;
+    sizeok = 0;
+    for (i = 0; i < members_dim; i++)
+    {
+	Dsymbol *s = (Dsymbol *)members->data[i];
+	s->semantic(sc);
+    }
+
+    if (sizeok == 2)
+    {	// semantic() failed because of forward references.
+	// Unwind what we did, and defer it for later
+	fields.setDim(0);
+	structsize = 0;
+	alignsize = 0;
+	structalign = 0;
+
+	sc = sc->pop();
+
+	scope = scx ? scx : new Scope(*sc);
+	scope->setNoFree();
+	scope->module->addDeferredSemantic(this);
+
+	//printf("\tsemantic('%s') failed\n", toChars());
+	return;
+    }
+
+    //printf("\tsemantic('%s') successful\n", toChars());
+
+    structsize = sc->offset;
+    //members->print();
+
+    /* Look for special member functions.
+     * They must be in this class, not in a base class.
+     */
+    ctor = (CtorDeclaration *)search(0, Id::ctor, 0);
+    if (ctor && ctor->toParent() != this)
+	ctor = NULL;
+
+//    dtor = (DtorDeclaration *)search(Id::dtor, 0);
+//    if (dtor && dtor->toParent() != this)
+//	dtor = NULL;
+
+//    inv = (InvariantDeclaration *)search(Id::classInvariant, 0);
+//    if (inv && inv->toParent() != this)
+//	inv = NULL;
+
+    // Can be in base class
+    aggNew    = (NewDeclaration *)search(0, Id::classNew, 0);
+    aggDelete = (DeleteDeclaration *)search(0, Id::classDelete, 0);
+
+    // If this class has no constructor, but base class does, create
+    // a constructor:
+    //    this() { }
+    if (!ctor && baseClass && baseClass->ctor)
+    {
+	//printf("Creating default this(){} for class %s\n", toChars());
+	ctor = new CtorDeclaration(0, 0, NULL, 0);
+	ctor->fbody = new CompoundStatement(0, new Statements());
+	members->push(ctor);
+	ctor->addMember(sc, this, 1);
+	*sc = scsave;
+	sc->offset = structsize;
+	ctor->semantic(sc);
+	defaultCtor = ctor;
+    }
+
+#if 0
+    if (baseClass)
+    {	if (!aggDelete)
+	    aggDelete = baseClass->aggDelete;
+	if (!aggNew)
+	    aggNew = baseClass->aggNew;
+    }
+#endif
+
+    // Allocate instance of each new interface
+    for (i = 0; i < vtblInterfaces->dim; i++)
+    {
+	BaseClass *b = (BaseClass *)vtblInterfaces->data[i];
+	unsigned thissize = PTRSIZE;
+
+	alignmember(structalign, thissize, &sc->offset);
+	assert(b->offset == 0);
+	b->offset = sc->offset;
+
+	// Take care of single inheritance offsets
+	while (b->baseInterfaces_dim)
+	{
+	    b = &b->baseInterfaces[0];
+	    b->offset = sc->offset;
+	}
+
+	sc->offset += thissize;
+	if (alignsize < thissize)
+	    alignsize = thissize;
+    }
+    structsize = sc->offset;
+    sizeok = 1;
+    Module::dprogress++;
+
+
+    sc->pop();
+
+#if 0 // Do not call until toObjfile() because of forward references
+    // Fill in base class vtbl[]s
+    for (i = 0; i < vtblInterfaces->dim; i++)
+    {
+	BaseClass *b = (BaseClass *)vtblInterfaces->data[i];
+
+	//b->fillVtbl(this, &b->vtbl, 1);
+    }
+#endif
+    //printf("-ClassDeclaration::semantic(%s), type = %p\n", toChars(), type);
+}
+
+void ClassDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    if (!isAnonymous())
+    {
+	buf->printf("%s ", kind());
+	buf->writestring(toChars());
+	if (baseclasses.dim)
+	    buf->writestring(" : ");
+    }
+    for (int i = 0; i < baseclasses.dim; i++)
+    {
+	BaseClass *b = (BaseClass *)baseclasses.data[i];
+
+	if (i)
+	    buf->writeByte(',');
+	//buf->writestring(b->base->ident->toChars());
+	b->type->toCBuffer(buf, NULL, hgs);
+    }
+    buf->writenl();
+    buf->writeByte('{');
+    buf->writenl();
+    for (int i = 0; i < members->dim; i++)
+    {
+	Dsymbol *s = (Dsymbol *)members->data[i];
+
+	buf->writestring("    ");
+	s->toCBuffer(buf, hgs);
+    }
+    buf->writestring("}");
+    buf->writenl();
+}
+
+#if 0
+void ClassDeclaration::defineRef(Dsymbol *s)
+{
+    ClassDeclaration *cd;
+
+    AggregateDeclaration::defineRef(s);
+    cd = s->isClassDeclaration();
+    baseType = cd->baseType;
+    cd->baseType = NULL;
+}
+#endif
+
+/*********************************************
+ * Determine if 'this' is a base class of cd.
+ * This is used to detect circular inheritance only.
+ */
+
+int ClassDeclaration::isBaseOf2(ClassDeclaration *cd)
+{
+    if (!cd)
+	return 0;
+    //printf("ClassDeclaration::isBaseOf2(this = '%s', cd = '%s')\n", toChars(), cd->toChars());
+    for (int i = 0; i < cd->baseclasses.dim; i++)
+    {	BaseClass *b = (BaseClass *)cd->baseclasses.data[i];
+
+	if (b->base == this || isBaseOf2(b->base))
+	    return 1;
+    }
+    return 0;
+}
+
+/*******************************************
+ * Determine if 'this' is a base class of cd.
+ */
+
+int ClassDeclaration::isBaseOf(ClassDeclaration *cd, int *poffset)
+{
+    //printf("ClassDeclaration::isBaseOf(this = '%s', cd = '%s')\n", toChars(), cd->toChars());
+    if (poffset)
+	*poffset = 0;
+    while (cd)
+    {
+	if (this == cd->baseClass)
+	    return 1;
+
+	/* cd->baseClass might not be set if cd is forward referenced.
+	 */
+	if (!cd->baseClass && cd->baseclasses.dim && !cd->isInterfaceDeclaration())
+	{
+	    cd->error("base class is forward referenced by %s", toChars());
+	}
+
+	cd = cd->baseClass;
+    }
+    return 0;
+}
+
+Dsymbol *ClassDeclaration::search(Loc loc, Identifier *ident, int flags)
+{
+    Dsymbol *s;
+
+    //printf("%s.ClassDeclaration::search('%s')\n", toChars(), ident->toChars());
+    if (scope)
+	semantic(scope);
+
+    if (!members || !symtab || scope)
+    {	error("is forward referenced when looking for '%s'", ident->toChars());
+	//*(char*)0=0;
+	return NULL;
+    }
+
+    s = ScopeDsymbol::search(loc, ident, flags);
+    if (!s)
+    {
+	// Search bases classes in depth-first, left to right order
+
+	int i;
+
+	for (i = 0; i < baseclasses.dim; i++)
+	{
+	    BaseClass *b = (BaseClass *)baseclasses.data[i];
+
+	    if (b->base)
+	    {
+		if (!b->base->symtab)
+		    error("base %s is forward referenced", b->base->ident->toChars());
+		else
+		{
+		    s = b->base->search(loc, ident, flags);
+		    if (s == this)	// happens if s is nested in this and derives from this
+			s = NULL;
+		    else if (s)
+			break;
+		}
+	    }
+	}
+    }
+    return s;
+}
+
+/****************
+ * Find virtual function matching identifier and type.
+ * Used to build virtual function tables for interface implementations.
+ */
+
+FuncDeclaration *ClassDeclaration::findFunc(Identifier *ident, TypeFunction *tf)
+{
+    //printf("ClassDeclaration::findFunc(%s, %s) %s\n", ident->toChars(), tf->toChars(), toChars());
+
+    ClassDeclaration *cd = this;
+    Array *vtbl = &cd->vtbl;
+    while (1)
+    {
+	for (size_t i = 0; i < vtbl->dim; i++)
+	{
+	    FuncDeclaration *fd = (FuncDeclaration *)vtbl->data[i];
+
+	    //printf("\t[%d] = %s\n", i, fd->toChars());
+	    if (ident == fd->ident &&
+		//tf->equals(fd->type)
+		fd->type->covariant(tf) == 1
+	       )
+	    {   //printf("\t\tfound\n");
+		return fd;
+	    }
+	    //else printf("\t\t%d\n", fd->type->covariant(tf));
+	}
+	if (!cd)
+	    break;
+	vtbl = &cd->vtblFinal;
+	cd = cd->baseClass;
+    }
+
+    return NULL;
+}
+
+void ClassDeclaration::interfaceSemantic(Scope *sc)
+{   int i;
+
+    vtblInterfaces = new BaseClasses();
+    vtblInterfaces->reserve(interfaces_dim);
+
+    for (i = 0; i < interfaces_dim; i++)
+    {
+	BaseClass *b = interfaces[i];
+
+	// If this is an interface, and it derives from a COM interface,
+	// then this is a COM interface too.
+	if (b->base->isCOMclass())
+	    com = 1;
+
+	vtblInterfaces->push(b);
+	b->copyBaseInterfaces(vtblInterfaces);
+    }
+}
+
+/****************************************
+ */
+
+int ClassDeclaration::isCOMclass()
+{
+    return com;
+}
+
+
+/****************************************
+ */
+
+int ClassDeclaration::isAbstract()
+{
+    if (isabstract)
+	return TRUE;
+    for (int i = 1; i < vtbl.dim; i++)
+    {
+	FuncDeclaration *fd = ((Dsymbol *)vtbl.data[i])->isFuncDeclaration();
+
+	//printf("\tvtbl[%d] = %p\n", i, fd);
+	if (!fd || fd->isAbstract())
+	{
+	    isabstract |= 1;
+	    return TRUE;
+	}
+    }
+    return FALSE;
+}
+
+/****************************************
+ * Returns !=0 if there's an extra member which is the 'this'
+ * pointer to the enclosing context (enclosing class or function)
+ */
+
+int ClassDeclaration::isNested()
+{
+    return isnested;
+}
+
+/****************************************
+ * Determine if slot 0 of the vtbl[] is reserved for something else.
+ * For class objects, yes, this is where the classinfo ptr goes.
+ * For COM interfaces, no.
+ * For non-COM interfaces, yes, this is where the Interface ptr goes.
+ */
+
+int ClassDeclaration::vtblOffset()
+{
+    return 1;
+}
+
+/****************************************
+ */
+
+char *ClassDeclaration::kind()
+{
+    return "class";
+}
+
+/****************************************
+ */
+
+void ClassDeclaration::addLocalClass(ClassDeclarations *aclasses)
+{
+    aclasses->push(this);
+}
+
+/********************************* InterfaceDeclaration ****************************/
+
+InterfaceDeclaration::InterfaceDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses)
+    : ClassDeclaration(loc, id, baseclasses)
+{
+    com = 0;
+    if (id == Id::IUnknown)		// IUnknown is the root of all COM objects
+	com = 1;
+}
+
+Dsymbol *InterfaceDeclaration::syntaxCopy(Dsymbol *s)
+{
+    InterfaceDeclaration *id;
+
+    if (s)
+	id = (InterfaceDeclaration *)s;
+    else
+	id = new InterfaceDeclaration(loc, ident, NULL);
+
+    ClassDeclaration::syntaxCopy(id);
+    return id;
+}
+
+void InterfaceDeclaration::semantic(Scope *sc)
+{   int i;
+
+    //printf("InterfaceDeclaration::semantic(%s), type = %p\n", toChars(), type);
+    if (!scope)
+    {	type = type->semantic(loc, sc);
+	handle = handle->semantic(loc, sc);
+    }
+    if (!members)			// if forward reference
+    {	//printf("\tinterface '%s' is forward referenced\n", toChars());
+	return;
+    }
+    if (symtab)			// if already done
+    {	if (!scope)
+	    return;
+    }
+    else
+	symtab = new DsymbolTable();
+
+    Scope *scx = NULL;
+    if (scope)
+    {	sc = scope;
+	scx = scope;		// save so we don't make redundant copies
+	scope = NULL;
+    }
+
+    // Expand any tuples in baseclasses[]
+    for (i = 0; i < baseclasses.dim; )
+    {	BaseClass *b = (BaseClass *)baseclasses.data[0];
+	b->type = b->type->semantic(loc, sc);
+	Type *tb = b->type->toBasetype();
+
+	if (tb->ty == Ttuple)
+	{   TypeTuple *tup = (TypeTuple *)tb;
+	    enum PROT protection = b->protection;
+	    baseclasses.remove(i);
+	    size_t dim = Argument::dim(tup->arguments);
+	    for (size_t j = 0; j < dim; j++)
+	    {	Argument *arg = Argument::getNth(tup->arguments, j);
+		b = new BaseClass(arg->type, protection);
+		baseclasses.insert(i + j, b);
+	    }
+	}
+	else
+	    i++;
+    }
+
+    // Check for errors, handle forward references
+    for (i = 0; i < baseclasses.dim; )
+    {	TypeClass *tc;
+	BaseClass *b;
+	Type *tb;
+
+	b = (BaseClass *)baseclasses.data[i];
+	b->type = b->type->semantic(loc, sc);
+	tb = b->type->toBasetype();
+	if (tb->ty == Tclass)
+	    tc = (TypeClass *)tb;
+	else
+	    tc = NULL;
+	if (!tc || !tc->sym->isInterfaceDeclaration())
+	{
+	    error("base type must be interface, not %s", b->type->toChars());
+	    baseclasses.remove(i);
+	    continue;
+	}
+	else
+	{
+	    // Check for duplicate interfaces
+	    for (size_t j = 0; j < i; j++)
+	    {
+		BaseClass *b2 = (BaseClass *)baseclasses.data[j];
+		if (b2->base == tc->sym)
+		    error("inherits from duplicate interface %s", b2->base->toChars());
+	    }
+
+	    b->base = tc->sym;
+	    if (b->base == this || isBaseOf2(b->base))
+	    {
+		error("circular inheritance of interface");
+		baseclasses.remove(i);
+		continue;
+	    }
+	    if (!b->base->symtab || b->base->scope)
+	    {
+		//error("forward reference of base class %s", baseClass->toChars());
+		// Forward reference of base, try again later
+		//printf("\ttry later, forward reference of base %s\n", b->base->toChars());
+		scope = scx ? scx : new Scope(*sc);
+		scope->setNoFree();
+		scope->module->addDeferredSemantic(this);
+		return;
+	    }
+	}
+	i++;
+    }
+
+    interfaces_dim = baseclasses.dim;
+    interfaces = (BaseClass **)baseclasses.data;
+
+    interfaceSemantic(sc);
+
+    if (vtblOffset())
+	vtbl.push(this);		// leave room at vtbl[0] for classinfo
+
+    // Cat together the vtbl[]'s from base interfaces
+    for (i = 0; i < interfaces_dim; i++)
+    {	BaseClass *b = interfaces[i];
+
+	// Skip if b has already appeared
+	for (int k = 0; k < i; k++)
+	{
+	    if (b == interfaces[i])
+		goto Lcontinue;
+	}
+
+	// Copy vtbl[] from base class
+	if (b->base->vtblOffset())
+	{   int d = b->base->vtbl.dim;
+	    if (d > 1)
+	    {
+		vtbl.reserve(d - 1);
+		for (int j = 1; j < d; j++)
+		    vtbl.push(b->base->vtbl.data[j]);
+	    }
+	}
+	else
+	{
+	    vtbl.append(&b->base->vtbl);
+	}
+
+      Lcontinue:
+	;
+    }
+
+    for (i = 0; i < members->dim; i++)
+    {
+	Dsymbol *s = (Dsymbol *)members->data[i];
+	s->addMember(sc, this, 1);
+    }
+
+    sc = sc->push(this);
+    sc->parent = this;
+    if (isCOMclass())
+	sc->linkage = LINKwindows;
+    sc->structalign = 8;
+    structalign = sc->structalign;
+    sc->offset = 8;
+    for (i = 0; i < members->dim; i++)
+    {
+	Dsymbol *s = (Dsymbol *)members->data[i];
+	s->semantic(sc);
+    }
+    //members->print();
+    sc->pop();
+    //printf("-InterfaceDeclaration::semantic(%s), type = %p\n", toChars(), type);
+}
+
+
+/*******************************************
+ * Determine if 'this' is a base class of cd.
+ * (Actually, if it is an interface supported by cd)
+ * Output:
+ *	*poffset	offset to start of class
+ *			OFFSET_RUNTIME	must determine offset at runtime
+ * Returns:
+ *	0	not a base
+ *	1	is a base
+ */
+
+int InterfaceDeclaration::isBaseOf(ClassDeclaration *cd, int *poffset)
+{
+    unsigned j;
+
+    //printf("%s.InterfaceDeclaration::isBaseOf(cd = '%s')\n", toChars(), cd->toChars());
+    assert(!baseClass);
+    for (j = 0; j < cd->interfaces_dim; j++)
+    {
+	BaseClass *b = cd->interfaces[j];
+
+	//printf("\tbase %s\n", b->base->toChars());
+	if (this == b->base)
+	{
+	    //printf("\tfound at offset %d\n", b->offset);
+	    if (poffset)
+	    {	*poffset = b->offset;
+		if (j && cd->isInterfaceDeclaration())
+		    *poffset = OFFSET_RUNTIME;
+	    }
+	    return 1;
+	}
+	if (isBaseOf(b, poffset))
+	{   if (j && poffset && cd->isInterfaceDeclaration())
+		*poffset = OFFSET_RUNTIME;
+	    return 1;
+	}
+    }
+
+    if (cd->baseClass && isBaseOf(cd->baseClass, poffset))
+	return 1;
+
+    if (poffset)
+	*poffset = 0;
+    return 0;
+}
+
+
+int InterfaceDeclaration::isBaseOf(BaseClass *bc, int *poffset)
+{
+    //printf("%s.InterfaceDeclaration::isBaseOf(bc = '%s')\n", toChars(), bc->base->toChars());
+    for (unsigned j = 0; j < bc->baseInterfaces_dim; j++)
+    {
+	BaseClass *b = &bc->baseInterfaces[j];
+
+	if (this == b->base)
+	{
+	    if (poffset)
+	    {	*poffset = b->offset;
+	    }
+	    return 1;
+	}
+	if (isBaseOf(b, poffset))
+	{
+	    return 1;
+	}
+    }
+    if (poffset)
+	*poffset = 0;
+    return 0;
+}
+
+/****************************************
+ * Determine if slot 0 of the vtbl[] is reserved for something else.
+ * For class objects, yes, this is where the classinfo ptr goes.
+ * For COM interfaces, no.
+ * For non-COM interfaces, yes, this is where the Interface ptr goes.
+ */
+
+int InterfaceDeclaration::vtblOffset()
+{
+    if (isCOMclass())
+	return 0;
+    return 1;
+}
+
+/*******************************************
+ */
+
+char *InterfaceDeclaration::kind()
+{
+    return "interface";
+}
+
+
+/******************************** BaseClass *****************************/
+
+BaseClass::BaseClass()
+{
+    memset(this, 0, sizeof(BaseClass));
+}
+
+BaseClass::BaseClass(Type *type, enum PROT protection)
+{
+    //printf("BaseClass(this = %p, '%s')\n", this, type->toChars());
+    this->type = type;
+    this->protection = protection;
+    base = NULL;
+    offset = 0;
+
+    baseInterfaces_dim = 0;
+    baseInterfaces = NULL;
+}
+
+/****************************************
+ * Fill in vtbl[] for base class based on member functions of class cd.
+ * Input:
+ *	vtbl		if !=NULL, fill it in
+ *	newinstance	!=0 means all entries must be filled in by members
+ *			of cd, not members of any base classes of cd.
+ * Returns:
+ *	!=0 if any entries were filled in by members of cd (not exclusively
+ *	by base classes)
+ */
+
+int BaseClass::fillVtbl(ClassDeclaration *cd, Array *vtbl, int newinstance)
+{
+    ClassDeclaration *id = base;
+    int j;
+    int result = 0;
+
+    //printf("BaseClass::fillVtbl(this='%s', cd='%s')\n", base->toChars(), cd->toChars());
+    if (vtbl)
+	vtbl->setDim(base->vtbl.dim);
+
+    // first entry is ClassInfo reference
+    for (j = base->vtblOffset(); j < base->vtbl.dim; j++)
+    {
+	FuncDeclaration *ifd = ((Dsymbol *)base->vtbl.data[j])->isFuncDeclaration();
+	FuncDeclaration *fd;
+	TypeFunction *tf;
+
+	//printf("        vtbl[%d] is '%s'\n", j, ifd ? ifd->toChars() : "null");
+
+	assert(ifd);
+	// Find corresponding function in this class
+	tf = (ifd->type->ty == Tfunction) ? (TypeFunction *)(ifd->type) : NULL;
+	fd = cd->findFunc(ifd->ident, tf);
+	if (fd && !fd->isAbstract())
+	{
+	    //printf("            found\n");
+	    // Check that calling conventions match
+	    if (fd->linkage != ifd->linkage)
+		fd->error("linkage doesn't match interface function");
+
+	    // Check that it is current
+	    if (newinstance &&
+		fd->toParent() != cd &&
+		ifd->toParent() == base)
+		cd->error("interface function %s.%s is not implemented",
+		    id->toChars(), ifd->ident->toChars());
+
+	    if (fd->toParent() == cd)
+		result = 1;
+	}
+	else
+	{
+	    //printf("            not found\n");
+	    // BUG: should mark this class as abstract?
+	    if (!cd->isAbstract())
+		cd->error("interface function %s.%s isn't implemented",
+		    id->toChars(), ifd->ident->toChars());
+	    fd = NULL;
+	}
+	if (vtbl)
+	    vtbl->data[j] = fd;
+    }
+
+    return result;
+}
+
+void BaseClass::copyBaseInterfaces(BaseClasses *vtblInterfaces)
+{
+    //printf("+copyBaseInterfaces(), %s\n", base->toChars());
+//    if (baseInterfaces_dim)
+//	return;
+
+    baseInterfaces_dim = base->interfaces_dim;
+    baseInterfaces = (BaseClass *)mem.calloc(baseInterfaces_dim, sizeof(BaseClass));
+
+    //printf("%s.copyBaseInterfaces()\n", base->toChars());
+    for (int i = 0; i < baseInterfaces_dim; i++)
+    {
+	BaseClass *b = &baseInterfaces[i];
+	BaseClass *b2 = base->interfaces[i];
+
+	assert(b2->vtbl.dim == 0);	// should not be filled yet
+	memcpy(b, b2, sizeof(BaseClass));
+
+	if (i)				// single inheritance is i==0
+	    vtblInterfaces->push(b);	// only need for M.I.
+	b->copyBaseInterfaces(vtblInterfaces);
+    }
+    //printf("-copyBaseInterfaces\n");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/complex_t.h	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,74 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright and Burton Radons
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#ifndef DMD_COMPLEX_T_H
+#define DMD_COMPLEX_T_H
+
+/* Roll our own complex type for compilers that don't support complex
+ */
+
+struct complex_t
+{
+    long double re;
+    long double im;    
+
+    complex_t() { this->re = 0; this->im = 0; }
+    complex_t(long double re) { this->re = re; this->im = 0; }
+    complex_t(long double re, long double im) { this->re = re; this->im = im; }
+
+    complex_t operator + (complex_t y) { complex_t r; r.re = re + y.re; r.im = im + y.im; return r; }
+    complex_t operator - (complex_t y) { complex_t r; r.re = re - y.re; r.im = im - y.im; return r; }
+    complex_t operator - () { complex_t r; r.re = -re; r.im = -im; return r; }
+    complex_t operator * (complex_t y) { return complex_t(re * y.re - im * y.im, im * y.re + re * y.im); }
+    
+    complex_t operator / (complex_t y)
+    {
+	long double abs_y_re = y.re < 0 ? -y.re : y.re;
+	long double abs_y_im = y.im < 0 ? -y.im : y.im;
+	long double r, den;
+
+	if (abs_y_re < abs_y_im)
+	{
+	    r = y.re / y.im;
+	    den = y.im + r * y.re;
+	    return complex_t((re * r + im) / den,
+			     (im * r - re) / den);
+	}
+	else
+	{
+	    r = y.im / y.re;
+	    den = y.re + r * y.im;
+	    return complex_t((re + r * im) / den,
+			     (im - r * re) / den);
+	}
+    }
+
+    operator bool () { return re || im; }
+
+    int operator == (complex_t y) { return re == y.re && im == y.im; }
+    int operator != (complex_t y) { return re != y.re || im != y.im; }
+};
+
+inline complex_t operator * (long double x, complex_t y) { return complex_t(x) * y; }
+inline complex_t operator * (complex_t x, long double y) { return x * complex_t(y); }
+inline complex_t operator / (complex_t x, long double y) { return x / complex_t(y); }
+
+
+inline long double creall(complex_t x)
+{
+    return x.re;
+}
+
+inline long double cimagl(complex_t x)
+{
+    return x.im;
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/cond.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,390 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "id.h"
+#include "init.h"
+#include "declaration.h"
+#include "identifier.h"
+#include "expression.h"
+#include "cond.h"
+#include "module.h"
+#include "template.h"
+#include "lexer.h"
+#ifdef _DH
+#include "mtype.h"
+#include "scope.h"
+#endif
+
+int findCondition(Array *ids, Identifier *ident)
+{
+    if (ids)
+    {
+	for (int i = 0; i < ids->dim; i++)
+	{
+	    char *id = (char *)ids->data[i];
+
+	    if (strcmp(id, ident->toChars()) == 0)
+		return TRUE;
+	}
+    }
+
+    return FALSE;
+}
+
+/* ============================================================ */
+
+Condition::Condition(Loc loc)
+{
+    this->loc = loc;
+    inc = 0;
+}
+
+/* ============================================================ */
+
+DVCondition::DVCondition(Module *mod, unsigned level, Identifier *ident)
+	: Condition(0)
+{
+    this->mod = mod;
+    this->level = level;
+    this->ident = ident;
+}
+
+Condition *DVCondition::syntaxCopy()
+{
+    return this;	// don't need to copy
+}
+
+/* ============================================================ */
+
+void DebugCondition::setGlobalLevel(unsigned level)
+{
+    global.params.debuglevel = level;
+}
+
+void DebugCondition::addGlobalIdent(char *ident)
+{
+    if (!global.params.debugids)
+	global.params.debugids = new Array();
+    global.params.debugids->push(ident);
+}
+
+
+DebugCondition::DebugCondition(Module *mod, unsigned level, Identifier *ident)
+    : DVCondition(mod, level, ident)
+{
+}
+
+int DebugCondition::include(Scope *sc, ScopeDsymbol *s)
+{
+    //printf("DebugCondition::include() level = %d, debuglevel = %d\n", level, global.params.debuglevel);
+    if (inc == 0)
+    {
+	inc = 2;
+	if (ident)
+	{
+	    if (findCondition(mod->debugids, ident))
+		inc = 1;
+	    else if (findCondition(global.params.debugids, ident))
+		inc = 1;
+	    else
+	    {	if (!mod->debugidsNot)
+		    mod->debugidsNot = new Array();
+		mod->debugidsNot->push(ident->toChars());
+	    }
+	}
+	else if (level <= global.params.debuglevel || level <= mod->debuglevel)
+	    inc = 1;
+    }
+    return (inc == 1);
+}
+
+void DebugCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    if (ident)
+	buf->printf("debug (%s)", ident->toChars());
+    else
+	buf->printf("debug (%u)", level);
+}
+
+/* ============================================================ */
+
+void VersionCondition::setGlobalLevel(unsigned level)
+{
+    global.params.versionlevel = level;
+}
+
+void VersionCondition::checkPredefined(Loc loc, char *ident)
+{
+    static char* reserved[] =
+    {
+	"DigitalMars", "X86", "X86_64",
+	"Windows", "Win32", "Win64",
+	"linux",
+	"LittleEndian", "BigEndian",
+	"all",
+	"none",
+    };
+
+    for (unsigned i = 0; i < sizeof(reserved) / sizeof(reserved[0]); i++)
+    {
+	if (strcmp(ident, reserved[i]) == 0)
+	    goto Lerror;
+    }
+
+    if (ident[0] == 'D' && ident[1] == '_')
+	goto Lerror;
+
+    return;
+
+  Lerror:
+    error(loc, "version identifier '%s' is reserved and cannot be set", ident);
+}
+
+void VersionCondition::addGlobalIdent(char *ident)
+{
+    checkPredefined(0, ident);
+    addPredefinedGlobalIdent(ident);
+}
+
+void VersionCondition::addPredefinedGlobalIdent(char *ident)
+{
+    if (!global.params.versionids)
+	global.params.versionids = new Array();
+    global.params.versionids->push(ident);
+}
+
+
+VersionCondition::VersionCondition(Module *mod, unsigned level, Identifier *ident)
+    : DVCondition(mod, level, ident)
+{
+}
+
+int VersionCondition::include(Scope *sc, ScopeDsymbol *s)
+{
+    //printf("VersionCondition::include() level = %d, versionlevel = %d\n", level, global.params.versionlevel);
+    //if (ident) printf("\tident = '%s'\n", ident->toChars());
+    if (inc == 0)
+    {
+	inc = 2;
+	if (ident)
+	{
+	    if (findCondition(mod->versionids, ident))
+		inc = 1;
+	    else if (findCondition(global.params.versionids, ident))
+		inc = 1;
+	    else
+	    {
+		if (!mod->versionidsNot)
+		    mod->versionidsNot = new Array();
+		mod->versionidsNot->push(ident->toChars());
+	    }
+	}
+	else if (level <= global.params.versionlevel || level <= mod->versionlevel)
+	    inc = 1;
+    }
+    return (inc == 1);
+}
+
+void VersionCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    if (ident)
+	buf->printf("version (%s)", ident->toChars());
+    else
+	buf->printf("version (%u)", level);
+}
+
+
+/**************************** StaticIfCondition *******************************/
+
+StaticIfCondition::StaticIfCondition(Loc loc, Expression *exp)
+    : Condition(loc)
+{
+    this->exp = exp;
+}
+
+Condition *StaticIfCondition::syntaxCopy()
+{
+    return new StaticIfCondition(loc, exp->syntaxCopy());
+}
+
+int StaticIfCondition::include(Scope *sc, ScopeDsymbol *s)
+{
+#if 0
+    printf("StaticIfCondition::include(sc = %p, s = %p)\n", sc, s);
+    if (s)
+    {
+	printf("\ts = '%s', kind = %s\n", s->toChars(), s->kind());
+    }
+#endif
+    if (inc == 0)
+    {
+	if (!sc)
+	{
+	    error(loc, "static if conditional cannot be at global scope");
+	    inc = 2;
+	    return 0;
+	}
+
+	sc = sc->push(sc->scopesym);
+	sc->sd = s;			// s gets any addMember()
+	sc->flags |= SCOPEstaticif;
+	Expression *e = exp->semantic(sc);
+	sc->pop();
+	e = e->optimize(WANTvalue | WANTinterpret);
+	if (e->isBool(TRUE))
+	    inc = 1;
+	else if (e->isBool(FALSE))
+	    inc = 2;
+	else
+	{
+	    e->error("expression %s is not constant or does not evaluate to a bool", e->toChars());
+	    inc = 2;
+	}
+    }
+    return (inc == 1);
+}
+
+void StaticIfCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("static if(");
+    exp->toCBuffer(buf, hgs);
+    buf->writeByte(')');
+}
+
+
+/**************************** IftypeCondition *******************************/
+
+IftypeCondition::IftypeCondition(Loc loc, Type *targ, Identifier *id, enum TOK tok, Type *tspec)
+    : Condition(loc)
+{
+    this->targ = targ;
+    this->id = id;
+    this->tok = tok;
+    this->tspec = tspec;
+}
+
+Condition *IftypeCondition::syntaxCopy()
+{
+    return new IftypeCondition(loc,
+	targ->syntaxCopy(),
+	id,
+	tok,
+	tspec ? tspec->syntaxCopy() : NULL);
+}
+
+int IftypeCondition::include(Scope *sc, ScopeDsymbol *sd)
+{
+    //printf("IftypeCondition::include()\n");
+    if (inc == 0)
+    {
+	if (!sc)
+	{
+	    error(loc, "iftype conditional cannot be at global scope");
+	    inc = 2;
+	    return 0;
+	}
+	unsigned errors = global.errors;
+	global.gag++;			// suppress printing of error messages
+	targ = targ->semantic(loc, sc);
+	global.gag--;
+	if (errors != global.errors)	// if any errors happened
+	{   inc = 2;			// then condition is false
+	    global.errors = errors;
+	}
+	else if (id && tspec)
+	{
+	    /* Evaluate to TRUE if targ matches tspec.
+	     * If TRUE, declare id as an alias for the specialized type.
+	     */
+
+	    MATCH m;
+	    TemplateTypeParameter tp(loc, id, NULL, NULL);
+
+	    TemplateParameters parameters;
+	    parameters.setDim(1);
+	    parameters.data[0] = (void *)&tp;
+
+	    Objects dedtypes;
+	    dedtypes.setDim(1);
+
+	    m = targ->deduceType(NULL, tspec, &parameters, &dedtypes);
+	    if (m == MATCHnomatch ||
+		(m != MATCHexact && tok == TOKequal))
+		inc = 2;
+	    else
+	    {
+		inc = 1;
+		Type *tded = (Type *)dedtypes.data[0];
+		if (!tded)
+		    tded = targ;
+		Dsymbol *s = new AliasDeclaration(loc, id, tded);
+		s->semantic(sc);
+		sc->insert(s);
+		if (sd)
+		    s->addMember(sc, sd, 1);
+	    }
+	}
+	else if (id)
+	{
+	    /* Declare id as an alias for type targ. Evaluate to TRUE
+	     */
+	    Dsymbol *s = new AliasDeclaration(loc, id, targ);
+	    s->semantic(sc);
+	    sc->insert(s);
+	    if (sd)
+		s->addMember(sc, sd, 1);
+	    inc = 1;
+	}
+	else if (tspec)
+	{
+	    /* Evaluate to TRUE if targ matches tspec
+	     */
+	    tspec = tspec->semantic(loc, sc);
+	    //printf("targ  = %s\n", targ->toChars());
+	    //printf("tspec = %s\n", tspec->toChars());
+	    if (tok == TOKcolon)
+	    {   if (targ->implicitConvTo(tspec))
+		    inc = 1;
+		else
+		    inc = 2;
+	    }
+	    else /* == */
+	    {	if (targ->equals(tspec))
+		    inc = 1;
+		else
+		    inc = 2;
+	    }
+	}
+	else
+	     inc = 1;
+	//printf("inc = %d\n", inc);
+    }
+    return (inc == 1);
+}
+
+void IftypeCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("iftype(");
+    targ->toCBuffer(buf, id, hgs);
+    if (tspec)
+    {
+	if (tok == TOKcolon)
+	    buf->writestring(" : ");
+	else
+	    buf->writestring(" == ");
+	tspec->toCBuffer(buf, NULL, hgs);
+    }
+    buf->writeByte(')');
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/cond.h	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,106 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#ifndef DMD_DEBCOND_H
+#define DMD_DEBCOND_H
+
+struct Expression;
+struct Identifier;
+struct OutBuffer;
+struct Module;
+struct Scope;
+struct ScopeDsymbol;
+#ifdef _DH
+#include "lexer.h" // dmdhg
+#endif
+enum TOK;
+#ifdef _DH
+struct HdrGenState;
+#endif
+
+int findCondition(Array *ids, Identifier *ident);
+
+struct Condition
+{
+    Loc loc;
+    int inc;		// 0: not computed yet
+			// 1: include
+			// 2: do not include
+
+    Condition(Loc loc);
+
+    virtual Condition *syntaxCopy() = 0;
+    virtual int include(Scope *sc, ScopeDsymbol *s) = 0;
+    virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs) = 0;
+};
+
+struct DVCondition : Condition
+{
+    unsigned level;
+    Identifier *ident;
+    Module *mod;
+
+    DVCondition(Module *mod, unsigned level, Identifier *ident);
+
+    Condition *syntaxCopy();
+};
+
+struct DebugCondition : DVCondition
+{
+    static void setGlobalLevel(unsigned level);
+    static void addGlobalIdent(char *ident);
+    static void addPredefinedGlobalIdent(char *ident);
+
+    DebugCondition(Module *mod, unsigned level, Identifier *ident);
+
+    int include(Scope *sc, ScopeDsymbol *s);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+};
+
+struct VersionCondition : DVCondition
+{
+    static void setGlobalLevel(unsigned level);
+    static void checkPredefined(Loc loc, char *ident);
+    static void addGlobalIdent(char *ident);
+    static void addPredefinedGlobalIdent(char *ident);
+
+    VersionCondition(Module *mod, unsigned level, Identifier *ident);
+
+    int include(Scope *sc, ScopeDsymbol *s);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+};
+
+struct StaticIfCondition : Condition
+{
+    Expression *exp;
+
+    StaticIfCondition(Loc loc, Expression *exp);
+    Condition *syntaxCopy();
+    int include(Scope *sc, ScopeDsymbol *s);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+};
+
+struct IftypeCondition : Condition
+{
+    /* iftype (targ id tok tspec)
+     */
+    Type *targ;
+    Identifier *id;	// can be NULL
+    enum TOK tok;	// ':' or '=='
+    Type *tspec;	// can be NULL
+
+    IftypeCondition(Loc loc, Type *targ, Identifier *id, enum TOK tok, Type *tspec);
+    Condition *syntaxCopy();
+    int include(Scope *sc, ScopeDsymbol *s);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+};
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/constfold.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,1461 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2007 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <math.h>
+
+#if __DMC__
+#include <complex.h>
+#endif
+
+#include "mem.h"
+#include "root.h"
+
+#include "mtype.h"
+#include "expression.h"
+#include "aggregate.h"
+#include "declaration.h"
+
+#ifdef IN_GCC
+#include "d-gcc-real.h"
+
+/* %% fix? */
+extern "C" bool real_isnan (const real_t *);
+#endif
+
+static real_t zero;	// work around DMC bug for now
+
+#define LOG 0
+
+Expression *expType(Type *type, Expression *e)
+{
+    if (type != e->type)
+    {
+	e = e->copy();
+	e->type = type;
+    }
+    return e;
+}
+
+/* ================================== isConst() ============================== */
+
+int Expression::isConst()
+{
+    //printf("Expression::isConst(): %s\n", toChars());
+    return 0;
+}
+
+int IntegerExp::isConst()
+{
+    return 1;
+}
+
+int RealExp::isConst()
+{
+    return 1;
+}
+
+int ComplexExp::isConst()
+{
+    return 1;
+}
+
+int SymOffExp::isConst()
+{
+    return 2;
+}
+
+/* =============================== constFold() ============================== */
+
+/* The constFold() functions were redundant with the optimize() ones,
+ * and so have been folded in with them.
+ */
+
+/* ========================================================================== */
+
+Expression *Neg(Type *type, Expression *e1)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    if (e1->type->isreal())
+    {
+	e = new RealExp(loc, -e1->toReal(), type);
+    }
+    else if (e1->type->isimaginary())
+    {
+	e = new RealExp(loc, -e1->toImaginary(), type);
+    }
+    else if (e1->type->iscomplex())
+    {
+	e = new ComplexExp(loc, -e1->toComplex(), type);
+    }
+    else
+	e = new IntegerExp(loc, -e1->toInteger(), type);
+    return e;
+}
+
+Expression *Com(Type *type, Expression *e1)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    e = new IntegerExp(loc, ~e1->toInteger(), type);
+    return e;
+}
+
+Expression *Not(Type *type, Expression *e1)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    e = new IntegerExp(loc, e1->isBool(0), type);
+    return e;
+}
+
+Expression *Bool(Type *type, Expression *e1)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    e = new IntegerExp(loc, e1->isBool(1), type);
+    return e;
+}
+
+Expression *Add(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+#if LOG
+    printf("Add(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars());
+#endif
+    if (type->isreal())
+    {
+	e = new RealExp(loc, e1->toReal() + e2->toReal(), type);
+    }
+    else if (type->isimaginary())
+    {
+	e = new RealExp(loc, e1->toImaginary() + e2->toImaginary(), type);
+    }
+    else if (type->iscomplex())
+    {
+	// This rigamarole is necessary so that -0.0 doesn't get
+	// converted to +0.0 by doing an extraneous add with +0.0
+	complex_t c1;
+	real_t r1;
+	real_t i1;
+
+	complex_t c2;
+	real_t r2;
+	real_t i2;
+
+	complex_t v;
+	int x;
+
+	if (e1->type->isreal())
+	{   r1 = e1->toReal();
+	    x = 0;
+	}
+	else if (e1->type->isimaginary())
+	{   i1 = e1->toImaginary();
+	    x = 3;
+	}
+	else
+	{   c1 = e1->toComplex();
+	    x = 6;
+	}
+
+	if (e2->type->isreal())
+	{   r2 = e2->toReal();
+	}
+	else if (e2->type->isimaginary())
+	{   i2 = e2->toImaginary();
+	    x += 1;
+	}
+	else
+	{   c2 = e2->toComplex();
+	    x += 2;
+	}
+
+	switch (x)
+	{
+#if __DMC__
+	    case 0+0:	v = (complex_t) (r1 + r2);	break;
+	    case 0+1:	v = r1 + i2 * I;		break;
+	    case 0+2:	v = r1 + c2;			break;
+	    case 3+0:	v = i1 * I + r2;		break;
+	    case 3+1:	v = (complex_t) ((i1 + i2) * I); break;
+	    case 3+2:	v = i1 * I + c2;		break;
+	    case 6+0:	v = c1 + r2;			break;
+	    case 6+1:	v = c1 + i2 * I;		break;
+	    case 6+2:	v = c1 + c2;			break;
+#else
+	    case 0+0:	v = complex_t(r1 + r2, 0);	break;
+	    case 0+1:	v = complex_t(r1, i2);		break;
+	    case 0+2:	v = complex_t(r1 + creall(c2), cimagl(c2));	break;
+	    case 3+0:	v = complex_t(r2, i1);		break;
+	    case 3+1:	v = complex_t(0, i1 + i2);	break;
+	    case 3+2:	v = complex_t(creall(c2), i1 + cimagl(c2));	break;
+	    case 6+0:	v = complex_t(creall(c1) + r2, cimagl(c2));	break;
+	    case 6+1:	v = complex_t(creall(c1), cimagl(c1) + i2);	break;
+	    case 6+2:	v = c1 + c2;			break;
+#endif
+	    default: assert(0);
+	}
+	e = new ComplexExp(loc, v, type);
+    }
+    else if (e1->op == TOKsymoff)
+    {
+	SymOffExp *soe = (SymOffExp *)e1;
+	e = new SymOffExp(loc, soe->var, soe->offset + e2->toInteger());
+	e->type = type;
+    }
+    else if (e2->op == TOKsymoff)
+    {
+	SymOffExp *soe = (SymOffExp *)e2;
+	e = new SymOffExp(loc, soe->var, soe->offset + e1->toInteger());
+	e->type = type;
+    }
+    else
+	e = new IntegerExp(loc, e1->toInteger() + e2->toInteger(), type);
+    return e;
+}
+
+
+Expression *Min(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    if (type->isreal())
+    {
+	e = new RealExp(loc, e1->toReal() - e2->toReal(), type);
+    }
+    else if (type->isimaginary())
+    {
+	e = new RealExp(loc, e1->toImaginary() - e2->toImaginary(), type);
+    }
+    else if (type->iscomplex())
+    {
+	// This rigamarole is necessary so that -0.0 doesn't get
+	// converted to +0.0 by doing an extraneous add with +0.0
+	complex_t c1;
+	real_t r1;
+	real_t i1;
+
+	complex_t c2;
+	real_t r2;
+	real_t i2;
+
+	complex_t v;
+	int x;
+
+	if (e1->type->isreal())
+	{   r1 = e1->toReal();
+	    x = 0;
+	}
+	else if (e1->type->isimaginary())
+	{   i1 = e1->toImaginary();
+	    x = 3;
+	}
+	else
+	{   c1 = e1->toComplex();
+	    x = 6;
+	}
+
+	if (e2->type->isreal())
+	{   r2 = e2->toReal();
+	}
+	else if (e2->type->isimaginary())
+	{   i2 = e2->toImaginary();
+	    x += 1;
+	}
+	else
+	{   c2 = e2->toComplex();
+	    x += 2;
+	}
+
+	switch (x)
+	{
+#if __DMC__
+	    case 0+0:	v = (complex_t) (r1 - r2);	break;
+	    case 0+1:	v = r1 - i2 * I;		break;
+	    case 0+2:	v = r1 - c2;			break;
+	    case 3+0:	v = i1 * I - r2;		break;
+	    case 3+1:	v = (complex_t) ((i1 - i2) * I); break;
+	    case 3+2:	v = i1 * I - c2;		break;
+	    case 6+0:	v = c1 - r2;			break;
+	    case 6+1:	v = c1 - i2 * I;		break;
+	    case 6+2:	v = c1 - c2;			break;
+#else
+	    case 0+0:	v = complex_t(r1 - r2, 0);	break;
+	    case 0+1:	v = complex_t(r1, -i2);		break;
+	    case 0+2:	v = complex_t(r1 - creall(c2), -cimagl(c2));	break;
+	    case 3+0:	v = complex_t(-r2, i1);		break;
+	    case 3+1:	v = complex_t(0, i1 - i2);	break;
+	    case 3+2:	v = complex_t(-creall(c2), i1 - cimagl(c2));	break;
+	    case 6+0:	v = complex_t(creall(c1) - r2, cimagl(c1));	break;
+	    case 6+1:	v = complex_t(creall(c1), cimagl(c1) - i2);	break;
+	    case 6+2:	v = c1 - c2;			break;
+#endif
+	    default: assert(0);
+	}
+	e = new ComplexExp(loc, v, type);
+    }
+    else if (e1->op == TOKsymoff)
+    {
+	SymOffExp *soe = (SymOffExp *)e1;
+	e = new SymOffExp(loc, soe->var, soe->offset - e2->toInteger());
+	e->type = type;
+    }
+    else
+    {
+	e = new IntegerExp(loc, e1->toInteger() - e2->toInteger(), type);
+    }
+    return e;
+}
+
+Expression *Mul(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    if (type->isfloating())
+    {   complex_t c;
+#ifdef IN_GCC
+	real_t r;
+#else
+	d_float80 r;
+#endif
+
+	if (e1->type->isreal())
+	{
+#if __DMC__
+	    c = e1->toReal() * e2->toComplex();
+#else
+	    r = e1->toReal();
+	    c = e2->toComplex();
+	    c = complex_t(r * creall(c), r * cimagl(c));
+#endif
+	}
+	else if (e1->type->isimaginary())
+	{
+#if __DMC__
+	    c = e1->toImaginary() * I * e2->toComplex();
+#else
+	    r = e1->toImaginary();
+	    c = e2->toComplex();
+	    c = complex_t(-r * cimagl(c), r * creall(c));
+#endif
+	}
+	else if (e2->type->isreal())
+	{
+#if __DMC__
+	    c = e2->toReal() * e1->toComplex();
+#else
+	    r = e2->toReal();
+	    c = e1->toComplex();
+	    c = complex_t(r * creall(c), r * cimagl(c));
+#endif
+	}
+	else if (e2->type->isimaginary())
+	{
+#if __DMC__
+	    c = e1->toComplex() * e2->toImaginary() * I;
+#else
+	    r = e2->toImaginary();
+	    c = e1->toComplex();
+	    c = complex_t(-r * cimagl(c), r * creall(c));
+#endif
+	}
+	else
+	    c = e1->toComplex() * e2->toComplex();
+
+	if (type->isreal())
+	    e = new RealExp(loc, creall(c), type);
+	else if (type->isimaginary())
+	    e = new RealExp(loc, cimagl(c), type);
+	else if (type->iscomplex())
+	    e = new ComplexExp(loc, c, type);
+	else
+	    assert(0);
+    }
+    else
+    {
+	e = new IntegerExp(loc, e1->toInteger() * e2->toInteger(), type);
+    }
+    return e;
+}
+
+Expression *Div(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    if (type->isfloating())
+    {   complex_t c;
+#ifdef IN_GCC
+	real_t r;
+#else
+	d_float80 r;
+#endif
+
+	//e1->type->print();
+	//e2->type->print();
+	if (e2->type->isreal())
+	{
+	    if (e1->type->isreal())
+	    {
+		e = new RealExp(loc, e1->toReal() / e2->toReal(), type);
+		return e;
+	    }
+#if __DMC__
+	    //r = e2->toReal();
+	    //c = e1->toComplex();
+	    //printf("(%Lg + %Lgi) / %Lg\n", creall(c), cimagl(c), r);
+
+	    c = e1->toComplex() / e2->toReal();
+#else
+	    r = e2->toReal();
+	    c = e1->toComplex();
+	    c = complex_t(creall(c) / r, cimagl(c) / r);
+#endif
+	}
+	else if (e2->type->isimaginary())
+	{
+#if __DMC__
+	    //r = e2->toImaginary();
+	    //c = e1->toComplex();
+	    //printf("(%Lg + %Lgi) / %Lgi\n", creall(c), cimagl(c), r);
+
+	    c = e1->toComplex() / (e2->toImaginary() * I);
+#else
+	    r = e2->toImaginary();
+	    c = e1->toComplex();
+	    c = complex_t(cimagl(c) / r, -creall(c) / r);
+#endif
+	}
+	else
+	{
+	    c = e1->toComplex() / e2->toComplex();
+	}
+
+	if (type->isreal())
+	    e = new RealExp(loc, creall(c), type);
+	else if (type->isimaginary())
+	    e = new RealExp(loc, cimagl(c), type);
+	else if (type->iscomplex())
+	    e = new ComplexExp(loc, c, type);
+	else
+	    assert(0);
+    }
+    else
+    {   sinteger_t n1;
+	sinteger_t n2;
+	sinteger_t n;
+
+	n1 = e1->toInteger();
+	n2 = e2->toInteger();
+	if (n2 == 0)
+	{   e2->error("divide by 0");
+	    e2 = new IntegerExp(0, 1, e2->type);
+	    n2 = 1;
+	}
+	if (e1->type->isunsigned() || e2->type->isunsigned())
+	    n = ((d_uns64) n1) / ((d_uns64) n2);
+	else
+	    n = n1 / n2;
+	e = new IntegerExp(loc, n, type);
+    }
+    return e;
+}
+
+Expression *Mod(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    if (type->isfloating())
+    {
+	complex_t c;
+
+	if (e2->type->isreal())
+	{   real_t r2 = e2->toReal();
+
+#ifdef __DMC__
+	    c = fmodl(e1->toReal(), r2) + fmodl(e1->toImaginary(), r2) * I;
+#elif defined(IN_GCC)
+	    c = complex_t(e1->toReal() % r2, e1->toImaginary() % r2);
+#else
+	    c = complex_t(fmodl(e1->toReal(), r2), fmodl(e1->toImaginary(), r2));
+#endif
+	}
+	else if (e2->type->isimaginary())
+	{   real_t i2 = e2->toImaginary();
+
+#ifdef __DMC__
+	    c = fmodl(e1->toReal(), i2) + fmodl(e1->toImaginary(), i2) * I;
+#elif defined(IN_GCC)
+	    c = complex_t(e1->toReal() % i2, e1->toImaginary() % i2);
+#else
+	    c = complex_t(fmodl(e1->toReal(), i2), fmodl(e1->toImaginary(), i2));
+#endif
+	}
+	else
+	    assert(0);
+
+	if (type->isreal())
+	    e = new RealExp(loc, creall(c), type);
+	else if (type->isimaginary())
+	    e = new RealExp(loc, cimagl(c), type);
+	else if (type->iscomplex())
+	    e = new ComplexExp(loc, c, type);
+	else
+	    assert(0);
+    }
+    else
+    {   sinteger_t n1;
+	sinteger_t n2;
+	sinteger_t n;
+
+	n1 = e1->toInteger();
+	n2 = e2->toInteger();
+	if (n2 == 0)
+	{   e2->error("divide by 0");
+	    e2 = new IntegerExp(0, 1, e2->type);
+	    n2 = 1;
+	}
+	if (e1->type->isunsigned() || e2->type->isunsigned())
+	    n = ((d_uns64) n1) % ((d_uns64) n2);
+	else
+	    n = n1 % n2;
+	e = new IntegerExp(loc, n, type);
+    }
+    return e;
+}
+
+Expression *Shl(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    e = new IntegerExp(loc, e1->toInteger() << e2->toInteger(), type);
+    return e;
+}
+
+Expression *Shr(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+    unsigned count;
+    integer_t value;
+
+    value = e1->toInteger();
+    count = e2->toInteger();
+    switch (e1->type->toBasetype()->ty)
+    {
+	case Tint8:
+		value = (d_int8)(value) >> count;
+		break;
+
+	case Tuns8:
+		value = (d_uns8)(value) >> count;
+		break;
+
+	case Tint16:
+		value = (d_int16)(value) >> count;
+		break;
+
+	case Tuns16:
+		value = (d_uns16)(value) >> count;
+		break;
+
+	case Tint32:
+		value = (d_int32)(value) >> count;
+		break;
+
+	case Tuns32:
+		value = (d_uns32)(value) >> count;
+		break;
+
+	case Tint64:
+		value = (d_int64)(value) >> count;
+		break;
+
+	case Tuns64:
+		value = (d_uns64)(value) >> count;
+		break;
+
+	default:
+		assert(0);
+    }
+    e = new IntegerExp(loc, value, type);
+    return e;
+}
+
+Expression *Ushr(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+    unsigned count;
+    integer_t value;
+
+    value = e1->toInteger();
+    count = e2->toInteger();
+    switch (e1->type->toBasetype()->ty)
+    {
+	case Tint8:
+	case Tuns8:
+		assert(0);		// no way to trigger this
+		value = (value & 0xFF) >> count;
+		break;
+
+	case Tint16:
+	case Tuns16:
+		assert(0);		// no way to trigger this
+		value = (value & 0xFFFF) >> count;
+		break;
+
+	case Tint32:
+	case Tuns32:
+		value = (value & 0xFFFFFFFF) >> count;
+		break;
+
+	case Tint64:
+	case Tuns64:
+		value = (d_uns64)(value) >> count;
+		break;
+
+	default:
+		assert(0);
+    }
+    e = new IntegerExp(loc, value, type);
+    return e;
+}
+
+Expression *And(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    e = new IntegerExp(loc, e1->toInteger() & e2->toInteger(), type);
+    return e;
+}
+
+Expression *Or(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    e = new IntegerExp(loc, e1->toInteger() | e2->toInteger(), type);
+    return e;
+}
+
+Expression *Xor(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    e = new IntegerExp(loc, e1->toInteger() ^ e2->toInteger(), type);
+    return e;
+}
+
+/* Also returns EXP_CANT_INTERPRET if cannot be computed.
+ */
+Expression *Equal(enum TOK op, Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+    int cmp;
+    real_t r1;
+    real_t r2;
+
+    //printf("Equal(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars());
+
+    assert(op == TOKequal || op == TOKnotequal);
+
+    if (e1->op == TOKstring && e2->op == TOKstring)
+    {	StringExp *es1 = (StringExp *)e1;
+	StringExp *es2 = (StringExp *)e2;
+
+	assert(es1->sz == es2->sz);
+	if (es1->len == es2->len &&
+	    memcmp(es1->string, es2->string, es1->sz * es1->len) == 0)
+	    cmp = 1;
+	else
+	    cmp = 0;
+    }
+    else if (e1->op == TOKarrayliteral && e2->op == TOKarrayliteral)
+    {   ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1;
+	ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
+
+	if ((!es1->elements || !es1->elements->dim) &&
+	    (!es2->elements || !es2->elements->dim))
+	    cmp = 1;		// both arrays are empty
+	else if (!es1->elements || !es2->elements)
+	    cmp = 0;
+	else if (es1->elements->dim != es2->elements->dim)
+	    cmp = 0;
+	else
+	{
+	    for (size_t i = 0; i < es1->elements->dim; i++)
+	    {   Expression *ee1 = (Expression *)es1->elements->data[i];
+		Expression *ee2 = (Expression *)es2->elements->data[i];
+
+		Expression *v = Equal(TOKequal, Type::tint32, ee1, ee2);
+		if (v == EXP_CANT_INTERPRET)
+		    return EXP_CANT_INTERPRET;
+		cmp = v->toInteger();
+		if (cmp == 0)
+		    break;
+	    }
+	}
+    }
+    else if (e1->op == TOKstructliteral && e2->op == TOKstructliteral)
+    {   StructLiteralExp *es1 = (StructLiteralExp *)e1;
+	StructLiteralExp *es2 = (StructLiteralExp *)e2;
+
+	if (es1->sd != es2->sd)
+	    cmp = 0;
+	else if ((!es1->elements || !es1->elements->dim) &&
+	    (!es2->elements || !es2->elements->dim))
+	    cmp = 1;		// both arrays are empty
+	else if (!es1->elements || !es2->elements)
+	    cmp = 0;
+	else if (es1->elements->dim != es2->elements->dim)
+	    cmp = 0;
+	else
+	{
+	    cmp = 1;
+	    for (size_t i = 0; i < es1->elements->dim; i++)
+	    {   Expression *ee1 = (Expression *)es1->elements->data[i];
+		Expression *ee2 = (Expression *)es2->elements->data[i];
+
+		if (ee1 == ee2)
+		    continue;
+		if (!ee1 || !ee2)
+		{   cmp = 0;
+		    break;
+		}
+		Expression *v = Equal(TOKequal, Type::tint32, ee1, ee2);
+		if (v == EXP_CANT_INTERPRET)
+		    return EXP_CANT_INTERPRET;
+		cmp = v->toInteger();
+		if (cmp == 0)
+		    break;
+	    }
+	}
+    }
+#if 0 // Should handle this
+    else if (e1->op == TOKarrayliteral && e2->op == TOKstring)
+    {
+    }
+#endif
+    else if (e1->isConst() != 1 || e2->isConst() != 1)
+	return EXP_CANT_INTERPRET;
+    else if (e1->type->isreal())
+    {
+	r1 = e1->toReal();
+	r2 = e2->toReal();
+	goto L1;
+    }
+    else if (e1->type->isimaginary())
+    {
+	r1 = e1->toImaginary();
+	r2 = e2->toImaginary();
+     L1:
+#if __DMC__
+	cmp = (r1 == r2);
+#else
+	if (isnan(r1) || isnan(r2))	// if unordered
+	{
+	    cmp = 0;
+	}
+	else
+	{
+	    cmp = (r1 == r2);
+	}
+#endif
+    }
+    else if (e1->type->iscomplex())
+    {
+	cmp = e1->toComplex() == e2->toComplex();
+    }
+    else if (e1->type->isintegral())
+    {
+	cmp = (e1->toInteger() == e2->toInteger());
+    }
+    else
+	return EXP_CANT_INTERPRET;
+    if (op == TOKnotequal)
+	cmp ^= 1;
+    e = new IntegerExp(loc, cmp, type);
+    return e;
+}
+
+Expression *Identity(enum TOK op, Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+    int cmp;
+
+    if (e1->op == TOKsymoff && e2->op == TOKsymoff)
+    {
+	SymOffExp *es1 = (SymOffExp *)e1;
+	SymOffExp *es2 = (SymOffExp *)e2;
+
+	cmp = (es1->var == es2->var && es1->offset == es2->offset);
+    }
+    else if (e1->isConst() == 1 && e2->isConst() == 1)
+	return Equal((op == TOKidentity) ? TOKequal : TOKnotequal,
+		type, e1, e2);
+    else
+	assert(0);
+    if (op == TOKnotidentity)
+	cmp ^= 1;
+    return new IntegerExp(loc, cmp, type);
+}
+
+
+Expression *Cmp(enum TOK op, Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+    integer_t n;
+    real_t r1;
+    real_t r2;
+
+    if (e1->type->isreal())
+    {
+	r1 = e1->toReal();
+	r2 = e2->toReal();
+	goto L1;
+    }
+    else if (e1->type->isimaginary())
+    {
+	r1 = e1->toImaginary();
+	r2 = e2->toImaginary();
+     L1:
+#if __DMC__
+	// DMC is the only compiler I know of that handles NAN arguments
+	// correctly in comparisons.
+	switch (op)
+	{
+	    case TOKlt:	   n = r1 <  r2;	break;
+	    case TOKle:	   n = r1 <= r2;	break;
+	    case TOKgt:	   n = r1 >  r2;	break;
+	    case TOKge:	   n = r1 >= r2;	break;
+
+	    case TOKleg:   n = r1 <>=  r2;	break;
+	    case TOKlg:	   n = r1 <>   r2;	break;
+	    case TOKunord: n = r1 !<>= r2;	break;
+	    case TOKue:	   n = r1 !<>  r2;	break;
+	    case TOKug:	   n = r1 !<=  r2;	break;
+	    case TOKuge:   n = r1 !<   r2;	break;
+	    case TOKul:	   n = r1 !>=  r2;	break;
+	    case TOKule:   n = r1 !>   r2;	break;
+
+	    default:
+		assert(0);
+	}
+#else
+	// Don't rely on compiler, handle NAN arguments separately
+#if IN_GCC
+	if (real_isnan(&r1) || real_isnan(&r2))	// if unordered
+#else
+	if (isnan(r1) || isnan(r2))	// if unordered
+#endif
+	{
+	    switch (op)
+	    {
+		case TOKlt:	n = 0;	break;
+		case TOKle:	n = 0;	break;
+		case TOKgt:	n = 0;	break;
+		case TOKge:	n = 0;	break;
+
+		case TOKleg:	n = 0;	break;
+		case TOKlg:	n = 0;	break;
+		case TOKunord:	n = 1;	break;
+		case TOKue:	n = 1;	break;
+		case TOKug:	n = 1;	break;
+		case TOKuge:	n = 1;	break;
+		case TOKul:	n = 1;	break;
+		case TOKule:	n = 1;	break;
+
+		default:
+		    assert(0);
+	    }
+	}
+	else
+	{
+	    switch (op)
+	    {
+		case TOKlt:	n = r1 <  r2;	break;
+		case TOKle:	n = r1 <= r2;	break;
+		case TOKgt:	n = r1 >  r2;	break;
+		case TOKge:	n = r1 >= r2;	break;
+
+		case TOKleg:	n = 1;		break;
+		case TOKlg:	n = r1 != r2;	break;
+		case TOKunord:	n = 0;		break;
+		case TOKue:	n = r1 == r2;	break;
+		case TOKug:	n = r1 >  r2;	break;
+		case TOKuge:	n = r1 >= r2;	break;
+		case TOKul:	n = r1 <  r2;	break;
+		case TOKule:	n = r1 <= r2;	break;
+
+		default:
+		    assert(0);
+	    }
+	}
+#endif
+    }
+    else if (e1->type->iscomplex())
+    {
+	assert(0);
+    }
+    else
+    {   sinteger_t n1;
+	sinteger_t n2;
+
+	n1 = e1->toInteger();
+	n2 = e2->toInteger();
+	if (e1->type->isunsigned() || e2->type->isunsigned())
+	{
+	    switch (op)
+	    {
+		case TOKlt:	n = ((d_uns64) n1) <  ((d_uns64) n2);	break;
+		case TOKle:	n = ((d_uns64) n1) <= ((d_uns64) n2);	break;
+		case TOKgt:	n = ((d_uns64) n1) >  ((d_uns64) n2);	break;
+		case TOKge:	n = ((d_uns64) n1) >= ((d_uns64) n2);	break;
+
+		case TOKleg:	n = 1;					break;
+		case TOKlg:	n = ((d_uns64) n1) != ((d_uns64) n2);	break;
+		case TOKunord:	n = 0;					break;
+		case TOKue:	n = ((d_uns64) n1) == ((d_uns64) n2);	break;
+		case TOKug:	n = ((d_uns64) n1) >  ((d_uns64) n2);	break;
+		case TOKuge:	n = ((d_uns64) n1) >= ((d_uns64) n2);	break;
+		case TOKul:	n = ((d_uns64) n1) <  ((d_uns64) n2);	break;
+		case TOKule:	n = ((d_uns64) n1) <= ((d_uns64) n2);	break;
+
+		default:
+		    assert(0);
+	    }
+	}
+	else
+	{
+	    switch (op)
+	    {
+		case TOKlt:	n = n1 <  n2;	break;
+		case TOKle:	n = n1 <= n2;	break;
+		case TOKgt:	n = n1 >  n2;	break;
+		case TOKge:	n = n1 >= n2;	break;
+
+		case TOKleg:	n = 1;		break;
+		case TOKlg:	n = n1 != n2;	break;
+		case TOKunord:	n = 0;		break;
+		case TOKue:	n = n1 == n2;	break;
+		case TOKug:	n = n1 >  n2;	break;
+		case TOKuge:	n = n1 >= n2;	break;
+		case TOKul:	n = n1 <  n2;	break;
+		case TOKule:	n = n1 <= n2;	break;
+
+		default:
+		    assert(0);
+	    }
+	}
+    }
+    e = new IntegerExp(loc, n, type);
+    return e;
+}
+
+/* Also returns EXP_CANT_INTERPRET if cannot be computed.
+ *  to:	type to cast to
+ *  type: type to paint the result
+ */
+
+Expression *Cast(Type *type, Type *to, Expression *e1)
+{   Expression *e = EXP_CANT_INTERPRET;
+    Loc loc = e1->loc;
+
+    //printf("Cast(type = %s, to = %s, e1 = %s)\n", type->toChars(), to->toChars(), e1->toChars());
+    //printf("e1->type = %s\n", e1->type->toChars());
+    if (type->equals(e1->type) && to->equals(type))
+	return e1;
+
+    if (e1->isConst() != 1)
+	return EXP_CANT_INTERPRET;
+
+    Type *tb = to->toBasetype();
+    if (tb->ty == Tbool)
+	e = new IntegerExp(loc, e1->toInteger() != 0, type);
+    else if (type->isintegral())
+    {
+	if (e1->type->isfloating())
+	{   integer_t result;
+	    real_t r = e1->toReal();
+
+	    switch (type->toBasetype()->ty)
+	    {
+		case Tint8:	result = (d_int8)r;	break;
+		case Tchar:
+		case Tuns8:	result = (d_uns8)r;	break;
+		case Tint16:	result = (d_int16)r;	break;
+		case Twchar:
+		case Tuns16:	result = (d_uns16)r;	break;
+		case Tint32:	result = (d_int32)r;	break;
+		case Tdchar:
+		case Tuns32:	result = (d_uns32)r;	break;
+		case Tint64:	result = (d_int64)r;	break;
+		case Tuns64:	result = (d_uns64)r;	break;
+		default:
+		    assert(0);
+	    }
+
+	    e = new IntegerExp(loc, result, type);
+	}
+	else if (type->isunsigned())
+	    e = new IntegerExp(loc, e1->toUInteger(), type);
+	else
+	    e = new IntegerExp(loc, e1->toInteger(), type);
+    }
+    else if (tb->isreal())
+    {   real_t value = e1->toReal();
+
+	e = new RealExp(loc, value, type);
+    }
+    else if (tb->isimaginary())
+    {   real_t value = e1->toImaginary();
+
+	e = new RealExp(loc, value, type);
+    }
+    else if (tb->iscomplex())
+    {   complex_t value = e1->toComplex();
+
+	e = new ComplexExp(loc, value, type);
+    }
+    else if (tb->isscalar())
+	e = new IntegerExp(loc, e1->toInteger(), type);
+    else if (tb->ty == Tvoid)
+	e = EXP_CANT_INTERPRET;
+    else if (tb->ty == Tstruct && e1->op == TOKint64)
+    {	// Struct = 0;
+	StructDeclaration *sd = tb->toDsymbol(NULL)->isStructDeclaration();
+	assert(sd);
+	Expressions *elements = new Expressions;
+	for (size_t i = 0; i < sd->fields.dim; i++)
+	{   Dsymbol *s = (Dsymbol *)sd->fields.data[i];
+	    VarDeclaration *v = s->isVarDeclaration();
+	    assert(v);
+
+	    Expression *exp = new IntegerExp(0);
+	    exp = Cast(v->type, v->type, exp);
+	    if (exp == EXP_CANT_INTERPRET)
+		return exp;
+	    elements->push(exp);
+	}
+	e = new StructLiteralExp(loc, sd, elements);
+	e->type = type;
+    }
+    else
+    {
+	error("cannot cast %s to %s", e1->type->toChars(), type->toChars());
+	e = new IntegerExp(loc, 0, type);
+    }
+    return e;
+}
+
+
+Expression *ArrayLength(Type *type, Expression *e1)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    if (e1->op == TOKstring)
+    {	StringExp *es1 = (StringExp *)e1;
+
+	e = new IntegerExp(loc, es1->len, type);
+    }
+    else if (e1->op == TOKarrayliteral)
+    {	ArrayLiteralExp *ale = (ArrayLiteralExp *)e1;
+	size_t dim;
+
+	dim = ale->elements ? ale->elements->dim : 0;
+	e = new IntegerExp(loc, dim, type);
+    }
+    else if (e1->op == TOKassocarrayliteral)
+    {	AssocArrayLiteralExp *ale = (AssocArrayLiteralExp *)e1;
+	size_t dim = ale->keys->dim;
+
+	e = new IntegerExp(loc, dim, type);
+    }
+    else
+	e = EXP_CANT_INTERPRET;
+    return e;
+}
+
+/* Also return EXP_CANT_INTERPRET if this fails
+ */
+Expression *Index(Type *type, Expression *e1, Expression *e2)
+{   Expression *e = EXP_CANT_INTERPRET;
+    Loc loc = e1->loc;
+
+    //printf("Index(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars());
+    assert(e1->type);
+    if (e1->op == TOKstring && e2->op == TOKint64)
+    {	StringExp *es1 = (StringExp *)e1;
+	uinteger_t i = e2->toInteger();
+
+	if (i >= es1->len)
+	    e1->error("string index %ju is out of bounds [0 .. %zu]", i, es1->len);
+	else
+	{   integer_t value;
+
+	    switch (es1->sz)
+	    {
+		case 1:
+		    value = ((unsigned char *)es1->string)[i];
+		    break;
+
+		case 2:
+		    value = ((unsigned short *)es1->string)[i];
+		    break;
+
+		case 4:
+		    value = ((unsigned int *)es1->string)[i];
+		    break;
+
+		default:
+		    assert(0);
+		    break;
+	    }
+	    e = new IntegerExp(loc, value, type);
+	}
+    }
+    else if (e1->type->toBasetype()->ty == Tsarray && e2->op == TOKint64)
+    {	TypeSArray *tsa = (TypeSArray *)e1->type->toBasetype();
+	uinteger_t length = tsa->dim->toInteger();
+	uinteger_t i = e2->toInteger();
+
+	if (i >= length)
+	{   e2->error("array index %ju is out of bounds %s[0 .. %ju]", i, e1->toChars(), length);
+	}
+	else if (e1->op == TOKarrayliteral && !e1->checkSideEffect(2))
+	{   ArrayLiteralExp *ale = (ArrayLiteralExp *)e1;
+	    e = (Expression *)ale->elements->data[i];
+	    e->type = type;
+	}
+    }
+    else if (e1->type->toBasetype()->ty == Tarray && e2->op == TOKint64)
+    {
+	uinteger_t i = e2->toInteger();
+
+	if (e1->op == TOKarrayliteral && !e1->checkSideEffect(2))
+	{   ArrayLiteralExp *ale = (ArrayLiteralExp *)e1;
+	    if (i >= ale->elements->dim)
+	    {   e2->error("array index %ju is out of bounds %s[0 .. %u]", i, e1->toChars(), ale->elements->dim);
+	    }
+	    else
+	    {	e = (Expression *)ale->elements->data[i];
+		e->type = type;
+	    }
+	}
+    }
+    else if (e1->op == TOKassocarrayliteral && !e1->checkSideEffect(2))
+    {
+	AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)e1;
+	/* Search the keys backwards, in case there are duplicate keys
+	 */
+	for (size_t i = ae->keys->dim; i;)
+	{
+	    i--;
+	    Expression *ekey = (Expression *)ae->keys->data[i];
+	    Expression *ex = Equal(TOKequal, Type::tbool, ekey, e2);
+	    if (ex == EXP_CANT_INTERPRET)
+		return ex;
+	    if (ex->isBool(TRUE))
+	    {	e = (Expression *)ae->values->data[i];
+		e->type = type;
+		break;
+	    }
+	}
+    }
+    return e;
+}
+
+/* Also return EXP_CANT_INTERPRET if this fails
+ */
+Expression *Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr)
+{   Expression *e = EXP_CANT_INTERPRET;
+    Loc loc = e1->loc;
+
+#if LOG
+    printf("Slice()\n");
+    if (lwr)
+    {	printf("\te1 = %s\n", e1->toChars());
+	printf("\tlwr = %s\n", lwr->toChars());
+	printf("\tupr = %s\n", upr->toChars());
+    }
+#endif
+    if (e1->op == TOKstring && lwr->op == TOKint64 && upr->op == TOKint64)
+    {	StringExp *es1 = (StringExp *)e1;
+	uinteger_t ilwr = lwr->toInteger();
+	uinteger_t iupr = upr->toInteger();
+
+	if (iupr > es1->len || ilwr > iupr)
+	    e1->error("string slice [%ju .. %ju] is out of bounds", ilwr, iupr);
+	else
+	{   integer_t value;
+	    void *s;
+	    size_t len = iupr - ilwr;
+	    int sz = es1->sz;
+	    StringExp *es;
+
+	    s = mem.malloc((len + 1) * sz);
+	    memcpy((unsigned char *)s, (unsigned char *)es1->string + ilwr * sz, len * sz);
+	    memset((unsigned char *)s + len * sz, 0, sz);
+
+	    es = new StringExp(loc, s, len, es1->postfix);
+	    es->sz = sz;
+	    es->committed = 1;
+	    es->type = type;
+	    e = es;
+	}
+    }
+    else if (e1->op == TOKarrayliteral &&
+	    lwr->op == TOKint64 && upr->op == TOKint64 &&
+	    !e1->checkSideEffect(2))
+    {	ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1;
+	uinteger_t ilwr = lwr->toInteger();
+	uinteger_t iupr = upr->toInteger();
+
+	if (iupr > es1->elements->dim || ilwr > iupr)
+	    e1->error("array slice [%ju .. %ju] is out of bounds", ilwr, iupr);
+	else
+	{
+	    Expressions *elements = new Expressions();
+	    elements->setDim(iupr - ilwr);
+	    memcpy(elements->data,
+		   es1->elements->data + ilwr,
+		   (iupr - ilwr) * sizeof(es1->elements->data[0]));
+	    e = new ArrayLiteralExp(e1->loc, elements);
+	    e->type = type;
+	}
+    }
+    return e;
+}
+
+/* Also return EXP_CANT_INTERPRET if this fails
+ */
+Expression *Cat(Type *type, Expression *e1, Expression *e2)
+{   Expression *e = EXP_CANT_INTERPRET;
+    Loc loc = e1->loc;
+    Type *t;
+
+    //printf("Cat(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars());
+
+    if (e1->op == TOKnull && e2->op == TOKint64)
+    {	e = e2;
+	goto L2;
+    }
+    else if (e1->op == TOKint64 && e2->op == TOKnull)
+    {	e = e1;
+     L2:
+	Type *tn = e->type->toBasetype();
+	if (tn->ty == Tchar || tn->ty == Twchar || tn->ty == Tdchar)
+	{
+	    // Create a StringExp
+	    void *s;
+	    StringExp *es;
+	    size_t len = 1;
+	    int sz = tn->size();
+	    integer_t v = e->toInteger();
+
+	    s = mem.malloc((len + 1) * sz);
+	    memcpy((unsigned char *)s, &v, sz);
+
+	    // Add terminating 0
+	    memset((unsigned char *)s + len * sz, 0, sz);
+
+	    es = new StringExp(loc, s, len);
+	    es->sz = sz;
+	    es->committed = 1;
+	    e = es;
+	}
+	else
+	{   // Create an ArrayLiteralExp
+	    Expressions *elements = new Expressions();
+	    elements->push(e);
+	    e = new ArrayLiteralExp(e->loc, elements);
+	}
+	e->type = type;
+	return e;
+    }
+    else if (e1->op == TOKstring && e2->op == TOKstring)
+    {
+	// Concatenate the strings
+	void *s;
+	StringExp *es1 = (StringExp *)e1;
+	StringExp *es2 = (StringExp *)e2;
+	StringExp *es;
+	Type *t;
+	size_t len = es1->len + es2->len;
+	int sz = es1->sz;
+
+	assert(sz == es2->sz);
+	s = mem.malloc((len + 1) * sz);
+	memcpy(s, es1->string, es1->len * sz);
+	memcpy((unsigned char *)s + es1->len * sz, es2->string, es2->len * sz);
+
+	// Add terminating 0
+	memset((unsigned char *)s + len * sz, 0, sz);
+
+	es = new StringExp(loc, s, len);
+	es->sz = sz;
+	es->committed = es1->committed | es2->committed;
+	if (es1->committed)
+	    t = es1->type;
+	else
+	    t = es2->type;
+	es->type = type;
+	e = es;
+    }
+    else if (e1->op == TOKstring && e2->op == TOKint64)
+    {
+	// Concatenate the strings
+	void *s;
+	StringExp *es1 = (StringExp *)e1;
+	StringExp *es;
+	Type *t;
+	size_t len = es1->len + 1;
+	int sz = es1->sz;
+	integer_t v = e2->toInteger();
+
+	s = mem.malloc((len + 1) * sz);
+	memcpy(s, es1->string, es1->len * sz);
+	memcpy((unsigned char *)s + es1->len * sz, &v, sz);
+
+	// Add terminating 0
+	memset((unsigned char *)s + len * sz, 0, sz);
+
+	es = new StringExp(loc, s, len);
+	es->sz = sz;
+	es->committed = es1->committed;
+	t = es1->type;
+	es->type = type;
+	e = es;
+    }
+    else if (e1->op == TOKint64 && e2->op == TOKstring)
+    {
+	// Concatenate the strings
+	void *s;
+	StringExp *es2 = (StringExp *)e2;
+	StringExp *es;
+	Type *t;
+	size_t len = 1 + es2->len;
+	int sz = es2->sz;
+	integer_t v = e1->toInteger();
+
+	s = mem.malloc((len + 1) * sz);
+	memcpy((unsigned char *)s, &v, sz);
+	memcpy((unsigned char *)s + sz, es2->string, es2->len * sz);
+
+	// Add terminating 0
+	memset((unsigned char *)s + len * sz, 0, sz);
+
+	es = new StringExp(loc, s, len);
+	es->sz = sz;
+	es->committed = es2->committed;
+	t = es2->type;
+	es->type = type;
+	e = es;
+    }
+    else if (e1->op == TOKarrayliteral && e2->op == TOKarrayliteral &&
+	e1->type->equals(e2->type))
+    {
+	// Concatenate the arrays
+	ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1;
+	ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
+
+	es1 = new ArrayLiteralExp(es1->loc, (Expressions *)es1->elements->copy());
+	es1->elements->insert(es1->elements->dim, es2->elements);
+	e = es1;
+
+	if (type->toBasetype()->ty == Tsarray)
+	{
+	    e->type = new TypeSArray(e1->type->toBasetype()->next, new IntegerExp(0, es1->elements->dim, Type::tindex));
+	    e->type = e->type->semantic(loc, NULL);
+	}
+	else
+	    e->type = type;
+    }
+    else if (e1->op == TOKarrayliteral &&
+	e1->type->toBasetype()->next->equals(e2->type))
+    {
+	ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1;
+
+	es1 = new ArrayLiteralExp(es1->loc, (Expressions *)es1->elements->copy());
+	es1->elements->push(e2);
+	e = es1;
+
+	if (type->toBasetype()->ty == Tsarray)
+	{
+	    e->type = new TypeSArray(e2->type, new IntegerExp(0, es1->elements->dim, Type::tindex));
+	    e->type = e->type->semantic(loc, NULL);
+	}
+	else
+	    e->type = type;
+    }
+    else if (e2->op == TOKarrayliteral &&
+	e2->type->toBasetype()->next->equals(e1->type))
+    {
+	ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
+
+	es2 = new ArrayLiteralExp(es2->loc, (Expressions *)es2->elements->copy());
+	es2->elements->shift(e1);
+	e = es2;
+
+	if (type->toBasetype()->ty == Tsarray)
+	{
+	    e->type = new TypeSArray(e1->type, new IntegerExp(0, es2->elements->dim, Type::tindex));
+	    e->type = e->type->semantic(loc, NULL);
+	}
+	else
+	    e->type = type;
+    }
+    else if (e1->op == TOKnull && e2->op == TOKstring)
+    {
+	t = e1->type;
+	e = e2;
+	goto L1;
+    }
+    else if (e1->op == TOKstring && e2->op == TOKnull)
+    {	e = e1;
+	t = e2->type;
+      L1:
+	Type *tb = t->toBasetype();
+	if (tb->ty == Tarray && tb->next->equals(e->type))
+	{   Expressions *expressions = new Expressions();
+	    expressions->push(e);
+	    e = new ArrayLiteralExp(loc, expressions);
+	    e->type = t;
+	}
+	if (!e->type->equals(type))
+	{   StringExp *se = (StringExp *)e->copy();
+	    e = se->castTo(NULL, type);
+	}
+    }
+    return e;
+}
+
+Expression *Ptr(Type *type, Expression *e1)
+{
+    //printf("Ptr(e1 = %s)\n", e1->toChars());
+    if (e1->op == TOKadd)
+    {	AddExp *ae = (AddExp *)e1;
+	if (ae->e1->op == TOKaddress && ae->e2->op == TOKint64)
+	{   AddrExp *ade = (AddrExp *)ae->e1;
+	    if (ade->e1->op == TOKstructliteral)
+	    {	StructLiteralExp *se = (StructLiteralExp *)ade->e1;
+		unsigned offset = ae->e2->toInteger();
+		Expression *e = se->getField(type, offset);
+		if (!e)
+		    e = EXP_CANT_INTERPRET;
+		return e;
+	    }
+	}
+    }
+    return EXP_CANT_INTERPRET;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/dchar.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,482 @@
+
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <assert.h>
+
+#include "dchar.h"
+#include "mem.h"
+
+#if M_UNICODE
+
+// Converts a char string to Unicode
+
+dchar *Dchar::dup(char *p)
+{
+    dchar *s;
+    size_t len;
+
+    if (!p)
+	return NULL;
+    len = strlen(p);
+    s = (dchar *)mem.malloc((len + 1) * sizeof(dchar));
+    for (unsigned i = 0; i < len; i++)
+    {
+	s[i] = (dchar)(p[i] & 0xFF);
+    }
+    s[len] = 0;
+    return s;
+}
+
+dchar *Dchar::memchr(dchar *p, int c, int count)
+{
+    int u;
+
+    for (u = 0; u < count; u++)
+    {
+	if (p[u] == c)
+	    return p + u;
+    }
+    return NULL;
+}
+
+#if _WIN32 && __DMC__
+__declspec(naked)
+unsigned Dchar::calcHash(const dchar *str, unsigned len)
+{
+    __asm
+    {
+	mov	ECX,4[ESP]
+	mov	EDX,8[ESP]
+	xor	EAX,EAX
+	test	EDX,EDX
+	je	L92
+
+LC8:	cmp	EDX,1
+	je	L98
+	cmp	EDX,2
+	je	LAE
+
+	add	EAX,[ECX]
+//	imul	EAX,EAX,025h
+	lea	EAX,[EAX][EAX*8]
+	add	ECX,4
+	sub	EDX,2
+	jmp	LC8
+
+L98:	mov	DX,[ECX]
+	and	EDX,0FFFFh
+	add	EAX,EDX
+	ret
+
+LAE:	add	EAX,[ECX]
+L92:	ret
+    }
+}
+#else
+hash_t Dchar::calcHash(const dchar *str, size_t len)
+{
+    unsigned hash = 0;
+
+    for (;;)
+    {
+	switch (len)
+	{
+	    case 0:
+		return hash;
+
+	    case 1:
+		hash += *(const uint16_t *)str;
+		return hash;
+
+	    case 2:
+		hash += *(const uint32_t *)str;
+		return hash;
+
+	    default:
+		hash += *(const uint32_t *)str;
+		hash *= 37;
+		str += 2;
+		len -= 2;
+		break;
+	}
+    }
+}
+#endif
+
+hash_t Dchar::icalcHash(const dchar *str, size_t len)
+{
+    hash_t hash = 0;
+
+    for (;;)
+    {
+	switch (len)
+	{
+	    case 0:
+		return hash;
+
+	    case 1:
+		hash += *(const uint16_t *)str | 0x20;
+		return hash;
+
+	    case 2:
+		hash += *(const uint32_t *)str | 0x200020;
+		return hash;
+
+	    default:
+		hash += *(const uint32_t *)str | 0x200020;
+		hash *= 37;
+		str += 2;
+		len -= 2;
+		break;
+	}
+    }
+}
+
+#elif MCBS
+
+hash_t Dchar::calcHash(const dchar *str, size_t len)
+{
+    hash_t hash = 0;
+
+    while (1)
+    {
+	switch (len)
+	{
+	    case 0:
+		return hash;
+
+	    case 1:
+		hash *= 37;
+		hash += *(const uint8_t *)str;
+		return hash;
+
+	    case 2:
+		hash *= 37;
+		hash += *(const uint16_t *)str;
+		return hash;
+
+	    case 3:
+		hash *= 37;
+		hash += (*(const uint16_t *)str << 8) +
+			((const uint8_t *)str)[2];
+		return hash;
+
+	    default:
+		hash *= 37;
+		hash += *(const uint32_t *)str;
+		str += 4;
+		len -= 4;
+		break;
+	}
+    }
+}
+
+#elif UTF8
+
+// Specification is: http://anubis.dkuug.dk/JTC1/SC2/WG2/docs/n1335
+
+char Dchar::mblen[256] =
+{
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+    2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+    3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
+    4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1,
+};
+
+dchar *Dchar::dec(dchar *pstart, dchar *p)
+{
+    while ((p[-1] & 0xC0) == 0x80)
+	p--;
+    return p;
+}
+
+int Dchar::get(dchar *p)
+{
+    unsigned c;
+    unsigned char *q = (unsigned char *)p;
+
+    c = q[0];
+    switch (mblen[c])
+    {
+	case 2:
+	    c = ((c    - 0xC0) << 6) |
+		 (q[1] - 0x80);
+	    break;
+
+	case 3:
+	    c = ((c    - 0xE0) << 12) |
+		((q[1] - 0x80) <<  6) |
+		 (q[2] - 0x80);
+	    break;
+
+	case 4:
+	    c = ((c    - 0xF0) << 18) |
+		((q[1] - 0x80) << 12) |
+		((q[2] - 0x80) <<  6) |
+		 (q[3] - 0x80);
+	    break;
+
+	case 5:
+	    c = ((c    - 0xF8) << 24) |
+		((q[1] - 0x80) << 18) |
+		((q[2] - 0x80) << 12) |
+		((q[3] - 0x80) <<  6) |
+		 (q[4] - 0x80);
+	    break;
+
+	case 6:
+	    c = ((c    - 0xFC) << 30) |
+		((q[1] - 0x80) << 24) |
+		((q[2] - 0x80) << 18) |
+		((q[3] - 0x80) << 12) |
+		((q[4] - 0x80) <<  6) |
+		 (q[5] - 0x80);
+	    break;
+    }
+    return c;
+}
+
+dchar *Dchar::put(dchar *p, unsigned c)
+{
+    if (c <= 0x7F)
+    {
+	*p++ = c;
+    }
+    else if (c <= 0x7FF)
+    {
+	p[0] = 0xC0 + (c >> 6);
+	p[1] = 0x80 + (c & 0x3F);
+	p += 2;
+    }
+    else if (c <= 0xFFFF)
+    {
+	p[0] = 0xE0 + (c >> 12);
+	p[1] = 0x80 + ((c >> 6) & 0x3F);
+	p[2] = 0x80 + (c & 0x3F);
+	p += 3;
+    }
+    else if (c <= 0x1FFFFF)
+    {
+	p[0] = 0xF0 + (c >> 18);
+	p[1] = 0x80 + ((c >> 12) & 0x3F);
+	p[2] = 0x80 + ((c >> 6) & 0x3F);
+	p[3] = 0x80 + (c & 0x3F);
+	p += 4;
+    }
+    else if (c <= 0x3FFFFFF)
+    {
+	p[0] = 0xF8 + (c >> 24);
+	p[1] = 0x80 + ((c >> 18) & 0x3F);
+	p[2] = 0x80 + ((c >> 12) & 0x3F);
+	p[3] = 0x80 + ((c >> 6) & 0x3F);
+	p[4] = 0x80 + (c & 0x3F);
+	p += 5;
+    }
+    else if (c <= 0x7FFFFFFF)
+    {
+	p[0] = 0xFC + (c >> 30);
+	p[1] = 0x80 + ((c >> 24) & 0x3F);
+	p[2] = 0x80 + ((c >> 18) & 0x3F);
+	p[3] = 0x80 + ((c >> 12) & 0x3F);
+	p[4] = 0x80 + ((c >> 6) & 0x3F);
+	p[5] = 0x80 + (c & 0x3F);
+	p += 6;
+    }
+    else
+	assert(0);		// not a UCS-4 character
+    return p;
+}
+
+hash_t Dchar::calcHash(const dchar *str, size_t len)
+{
+    hash_t hash = 0;
+
+    while (1)
+    {
+	switch (len)
+	{
+	    case 0:
+		return hash;
+
+	    case 1:
+		hash *= 37;
+		hash += *(const uint8_t *)str;
+		return hash;
+
+	    case 2:
+		hash *= 37;
+#if __I86__
+		hash += *(const uint16_t *)str;
+#else
+		hash += str[0] * 256 + str[1];
+#endif
+		return hash;
+
+	    case 3:
+		hash *= 37;
+#if __I86__
+		hash += (*(const uint16_t *)str << 8) +
+			((const uint8_t *)str)[2];
+#else
+		hash += (str[0] * 256 + str[1]) * 256 + str[2];
+#endif
+		return hash;
+
+	    default:
+		hash *= 37;
+#if __I86__
+		hash += *(const uint32_t *)str;
+#else
+		hash += ((str[0] * 256 + str[1]) * 256 + str[2]) * 256 + str[3];
+#endif
+
+		str += 4;
+		len -= 4;
+		break;
+	}
+    }
+}
+
+#else // ascii
+
+hash_t Dchar::calcHash(const dchar *str, size_t len)
+{
+    hash_t hash = 0;
+
+    while (1)
+    {
+	switch (len)
+	{
+	    case 0:
+		return hash;
+
+	    case 1:
+		hash *= 37;
+		hash += *(const uint8_t *)str;
+		return hash;
+
+	    case 2:
+		hash *= 37;
+#if __I86__
+		hash += *(const uint16_t *)str;
+#else
+		hash += str[0] * 256 + str[1];
+#endif
+		return hash;
+
+	    case 3:
+		hash *= 37;
+#if __I86__
+		hash += (*(const uint16_t *)str << 8) +
+			((const uint8_t *)str)[2];
+#else
+		hash += (str[0] * 256 + str[1]) * 256 + str[2];
+#endif
+		return hash;
+
+	    default:
+		hash *= 37;
+#if __I86__
+		hash += *(const uint32_t *)str;
+#else
+		hash += ((str[0] * 256 + str[1]) * 256 + str[2]) * 256 + str[3];
+#endif
+		str += 4;
+		len -= 4;
+		break;
+	}
+    }
+}
+
+hash_t Dchar::icalcHash(const dchar *str, size_t len)
+{
+    hash_t hash = 0;
+
+    while (1)
+    {
+	switch (len)
+	{
+	    case 0:
+		return hash;
+
+	    case 1:
+		hash *= 37;
+		hash += *(const uint8_t *)str | 0x20;
+		return hash;
+
+	    case 2:
+		hash *= 37;
+		hash += *(const uint16_t *)str | 0x2020;
+		return hash;
+
+	    case 3:
+		hash *= 37;
+		hash += ((*(const uint16_t *)str << 8) +
+			 ((const uint8_t *)str)[2]) | 0x202020;
+		return hash;
+
+	    default:
+		hash *= 37;
+		hash += *(const uint32_t *)str | 0x20202020;
+		str += 4;
+		len -= 4;
+		break;
+	}
+    }
+}
+
+#endif
+
+#if 0
+#include <stdio.h>
+
+void main()
+{
+    // Print out values to hardcode into Dchar::mblen[]
+    int c;
+    int s;
+
+    for (c = 0; c < 256; c++)
+    {
+	s = 1;
+	if (c >= 0xC0 && c <= 0xDF)
+	    s = 2;
+	if (c >= 0xE0 && c <= 0xEF)
+	    s = 3;
+	if (c >= 0xF0 && c <= 0xF7)
+	    s = 4;
+	if (c >= 0xF8 && c <= 0xFB)
+	    s = 5;
+	if (c >= 0xFC && c <= 0xFD)
+	    s = 6;
+
+	printf("%d", s);
+	if ((c & 15) == 15)
+	    printf(",\n");
+	else
+	    printf(",");
+    }
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/dchar.h	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,194 @@
+
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+
+#ifndef DCHAR_H
+#define DCHAR_H
+
+#if __GNUC__ && !_WIN32
+#include "gnuc.h"
+#endif
+
+#if _MSC_VER
+    // Disable useless warnings about unreferenced functions
+    #pragma warning (disable : 4514)
+#endif
+
+//#include "root.h"
+typedef size_t hash_t;
+
+#undef TEXT
+
+// NOTE: All functions accepting pointer arguments must not be NULL
+
+#if M_UNICODE
+
+#include <string.h>
+#include <wchar.h>
+
+typedef wchar_t dchar;
+#define TEXT(x)		L##x
+
+#define Dchar_mbmax	1
+
+struct Dchar
+{
+    static dchar *inc(dchar *p) { return p + 1; }
+    static dchar *dec(dchar *pstart, dchar *p) { (void)pstart; return p - 1; }
+    static int len(const dchar *p) { return wcslen(p); }
+    static dchar get(dchar *p) { return *p; }
+    static dchar getprev(dchar *pstart, dchar *p) { (void)pstart; return p[-1]; }
+    static dchar *put(dchar *p, dchar c) { *p = c; return p + 1; }
+    static int cmp(dchar *s1, dchar *s2)
+    {
+#if __DMC__
+	if (!*s1 && !*s2)	// wcscmp is broken
+	    return 0;
+#endif
+	return wcscmp(s1, s2);
+#if 0
+	return (*s1 == *s2)
+	    ? wcscmp(s1, s2)
+	    : ((int)*s1 - (int)*s2);
+#endif
+    }
+    static int memcmp(const dchar *s1, const dchar *s2, int nchars) { return ::memcmp(s1, s2, nchars * sizeof(dchar)); }
+    static int isDigit(dchar c) { return '0' <= c && c <= '9'; }
+    static int isAlpha(dchar c) { return iswalpha(c); }
+    static int isUpper(dchar c) { return iswupper(c); }
+    static int isLower(dchar c) { return iswlower(c); }
+    static int isLocaleUpper(dchar c) { return isUpper(c); }
+    static int isLocaleLower(dchar c) { return isLower(c); }
+    static int toLower(dchar c) { return isUpper(c) ? towlower(c) : c; }
+    static int toLower(dchar *p) { return toLower(*p); }
+    static int toUpper(dchar c) { return isLower(c) ? towupper(c) : c; }
+    static dchar *dup(dchar *p) { return ::_wcsdup(p); }	// BUG: out of memory?
+    static dchar *dup(char *p);
+    static dchar *chr(dchar *p, unsigned c) { return wcschr(p, (dchar)c); }
+    static dchar *rchr(dchar *p, unsigned c) { return wcsrchr(p, (dchar)c); }
+    static dchar *memchr(dchar *p, int c, int count);
+    static dchar *cpy(dchar *s1, dchar *s2) { return wcscpy(s1, s2); }
+    static dchar *str(dchar *s1, dchar *s2) { return wcsstr(s1, s2); }
+    static hash_t calcHash(const dchar *str, size_t len);
+
+    // Case insensitive versions
+    static int icmp(dchar *s1, dchar *s2) { return wcsicmp(s1, s2); }
+    static int memicmp(const dchar *s1, const dchar *s2, int nchars) { return ::wcsnicmp(s1, s2, nchars); }
+    static hash_t icalcHash(const dchar *str, size_t len);
+};
+
+#elif MCBS
+
+#include <limits.h>
+#include <mbstring.h>
+
+typedef char dchar;
+#define TEXT(x)		x
+
+#define Dchar_mbmax	MB_LEN_MAX
+
+#elif UTF8
+
+typedef char dchar;
+#define TEXT(x)		x
+
+#define Dchar_mbmax	6
+
+struct Dchar
+{
+    static char mblen[256];
+
+    static dchar *inc(dchar *p) { return p + mblen[*p & 0xFF]; }
+    static dchar *dec(dchar *pstart, dchar *p);
+    static int len(const dchar *p) { return strlen(p); }
+    static int get(dchar *p);
+    static int getprev(dchar *pstart, dchar *p)
+	{ return *dec(pstart, p) & 0xFF; }
+    static dchar *put(dchar *p, unsigned c);
+    static int cmp(dchar *s1, dchar *s2) { return strcmp(s1, s2); }
+    static int memcmp(const dchar *s1, const dchar *s2, int nchars) { return ::memcmp(s1, s2, nchars); }
+    static int isDigit(dchar c) { return '0' <= c && c <= '9'; }
+    static int isAlpha(dchar c) { return c <= 0x7F ? isalpha(c) : 0; }
+    static int isUpper(dchar c) { return c <= 0x7F ? isupper(c) : 0; }
+    static int isLower(dchar c) { return c <= 0x7F ? islower(c) : 0; }
+    static int isLocaleUpper(dchar c) { return isUpper(c); }
+    static int isLocaleLower(dchar c) { return isLower(c); }
+    static int toLower(dchar c) { return isUpper(c) ? tolower(c) : c; }
+    static int toLower(dchar *p) { return toLower(*p); }
+    static int toUpper(dchar c) { return isLower(c) ? toupper(c) : c; }
+    static dchar *dup(dchar *p) { return ::strdup(p); }	// BUG: out of memory?
+    static dchar *chr(dchar *p, int c) { return strchr(p, c); }
+    static dchar *rchr(dchar *p, int c) { return strrchr(p, c); }
+    static dchar *memchr(dchar *p, int c, int count)
+	{ return (dchar *)::memchr(p, c, count); }
+    static dchar *cpy(dchar *s1, dchar *s2) { return strcpy(s1, s2); }
+    static dchar *str(dchar *s1, dchar *s2) { return strstr(s1, s2); }
+    static hash_t calcHash(const dchar *str, size_t len);
+
+    // Case insensitive versions
+    static int icmp(dchar *s1, dchar *s2) { return _mbsicmp(s1, s2); }
+    static int memicmp(const dchar *s1, const dchar *s2, int nchars) { return ::_mbsnicmp(s1, s2, nchars); }
+};
+
+#else
+
+#include <string.h>
+
+#ifndef GCC_SAFE_DMD
+#include <ctype.h>
+#endif
+
+typedef char dchar;
+#define TEXT(x)		x
+
+#define Dchar_mbmax	1
+
+struct Dchar
+{
+    static dchar *inc(dchar *p) { return p + 1; }
+    static dchar *dec(dchar *pstart, dchar *p) { return p - 1; }
+    static int len(const dchar *p) { return strlen(p); }
+    static int get(dchar *p) { return *p & 0xFF; }
+    static int getprev(dchar *pstart, dchar *p) { return p[-1] & 0xFF; }
+    static dchar *put(dchar *p, unsigned c) { *p = c; return p + 1; }
+    static int cmp(dchar *s1, dchar *s2) { return strcmp(s1, s2); }
+    static int memcmp(const dchar *s1, const dchar *s2, int nchars) { return ::memcmp(s1, s2, nchars); }
+    static int isDigit(dchar c) { return '0' <= c && c <= '9'; }
+#ifndef GCC_SAFE_DMD
+    static int isAlpha(dchar c) { return isalpha(c); }
+    static int isUpper(dchar c) { return isupper(c); }
+    static int isLower(dchar c) { return islower(c); }
+    static int isLocaleUpper(dchar c) { return isupper(c); }
+    static int isLocaleLower(dchar c) { return islower(c); }
+    static int toLower(dchar c) { return isupper(c) ? tolower(c) : c; }
+    static int toLower(dchar *p) { return toLower(*p); }
+    static int toUpper(dchar c) { return islower(c) ? toupper(c) : c; }
+    static dchar *dup(dchar *p) { return ::strdup(p); }	// BUG: out of memory?
+#endif
+    static dchar *chr(dchar *p, int c) { return strchr(p, c); }
+    static dchar *rchr(dchar *p, int c) { return strrchr(p, c); }
+    static dchar *memchr(dchar *p, int c, int count)
+	{ return (dchar *)::memchr(p, c, count); }
+    static dchar *cpy(dchar *s1, dchar *s2) { return strcpy(s1, s2); }
+    static dchar *str(dchar *s1, dchar *s2) { return strstr(s1, s2); }
+    static hash_t calcHash(const dchar *str, size_t len);
+
+    // Case insensitive versions
+#ifdef __GNUC__
+    static int icmp(dchar *s1, dchar *s2) { return strcasecmp(s1, s2); }
+#else
+    static int icmp(dchar *s1, dchar *s2) { return stricmp(s1, s2); }
+#endif
+    static int memicmp(const dchar *s1, const dchar *s2, int nchars) { return ::memicmp(s1, s2, nchars); }
+    static hash_t icalcHash(const dchar *str, size_t len);
+};
+
+#endif
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/declaration.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,1260 @@
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2007 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "init.h"
+#include "declaration.h"
+#include "attrib.h"
+#include "mtype.h"
+#include "template.h"
+#include "scope.h"
+#include "aggregate.h"
+#include "module.h"
+#include "id.h"
+#include "expression.h"
+#include "hdrgen.h"
+
+/********************************* Declaration ****************************/
+
+Declaration::Declaration(Identifier *id)
+    : Dsymbol(id)
+{
+    type = NULL;
+    storage_class = STCundefined;
+    protection = PROTundefined;
+    linkage = LINKdefault;
+}
+
+void Declaration::semantic(Scope *sc)
+{
+}
+
+char *Declaration::kind()
+{
+    return "declaration";
+}
+
+unsigned Declaration::size(Loc loc)
+{
+    assert(type);
+    return type->size();
+}
+
+int Declaration::isStaticConstructor()
+{
+    return FALSE;
+}
+
+int Declaration::isStaticDestructor()
+{
+    return FALSE;
+}
+
+int Declaration::isDelete()
+{
+    return FALSE;
+}
+
+int Declaration::isDataseg()
+{
+    return FALSE;
+}
+
+int Declaration::isCodeseg()
+{
+    return FALSE;
+}
+
+enum PROT Declaration::prot()
+{
+    return protection;
+}
+
+/********************************* TupleDeclaration ****************************/
+
+TupleDeclaration::TupleDeclaration(Loc loc, Identifier *id, Objects *objects)
+    : Declaration(id)
+{
+    this->type = NULL;
+    this->objects = objects;
+    this->isexp = 0;
+    this->tupletype = NULL;
+}
+
+Dsymbol *TupleDeclaration::syntaxCopy(Dsymbol *s)
+{
+    assert(0);
+    return NULL;
+}
+
+char *TupleDeclaration::kind()
+{
+    return "tuple";
+}
+
+Type *TupleDeclaration::getType()
+{
+    /* If this tuple represents a type, return that type
+     */
+
+    //printf("TupleDeclaration::getType() %s\n", toChars());
+    if (isexp)
+	return NULL;
+    if (!tupletype)
+    {
+	/* It's only a type tuple if all the Object's are types
+	 */
+	for (size_t i = 0; i < objects->dim; i++)
+	{   Object *o = (Object *)objects->data[i];
+
+	    if (o->dyncast() != DYNCAST_TYPE)
+	    {
+		//printf("\tnot[%d], %p, %d\n", i, o, o->dyncast());
+		return NULL;
+	    }
+	}
+
+	/* We know it's a type tuple, so build the TypeTuple
+	 */
+	Arguments *args = new Arguments();
+	args->setDim(objects->dim);
+	OutBuffer buf;
+	for (size_t i = 0; i < objects->dim; i++)
+	{   Type *t = (Type *)objects->data[i];
+
+	    //printf("type = %s\n", t->toChars());
+#if 0
+	    buf.printf("_%s_%d", ident->toChars(), i);
+	    char *name = (char *)buf.extractData();
+	    Identifier *id = new Identifier(name, TOKidentifier);
+	    Argument *arg = new Argument(STCin, t, id, NULL);
+#else
+	    Argument *arg = new Argument(STCin, t, NULL, NULL);
+#endif
+	    args->data[i] = (void *)arg;
+	}
+
+	tupletype = new TypeTuple(args);
+    }
+
+    return tupletype;
+}
+
+int TupleDeclaration::needThis()
+{
+    //printf("TupleDeclaration::needThis(%s)\n", toChars());
+    for (size_t i = 0; i < objects->dim; i++)
+    {   Object *o = (Object *)objects->data[i];
+	if (o->dyncast() == DYNCAST_EXPRESSION)
+	{   Expression *e = (Expression *)o;
+	    if (e->op == TOKdsymbol)
+	    {	DsymbolExp *ve = (DsymbolExp *)e;
+		Declaration *d = ve->s->isDeclaration();
+		if (d && d->needThis())
+		{
+		    return 1;
+		}
+	    }
+	}
+    }
+    return 0;
+}
+
+/********************************* TypedefDeclaration ****************************/
+
+TypedefDeclaration::TypedefDeclaration(Loc loc, Identifier *id, Type *basetype, Initializer *init)
+    : Declaration(id)
+{
+    this->type = new TypeTypedef(this);
+    this->basetype = basetype->toBasetype();
+    this->init = init;
+#ifdef _DH
+    this->htype = NULL;
+    this->hbasetype = NULL;
+#endif
+    this->sem = 0;
+    this->inuse = 0;
+    this->loc = loc;
+    this->sinit = NULL;
+}
+
+Dsymbol *TypedefDeclaration::syntaxCopy(Dsymbol *s)
+{
+    Type *basetype = this->basetype->syntaxCopy();
+
+    Initializer *init = NULL;
+    if (this->init)
+	init = this->init->syntaxCopy();
+
+    assert(!s);
+    TypedefDeclaration *st;
+    st = new TypedefDeclaration(loc, ident, basetype, init);
+#ifdef _DH
+    // Syntax copy for header file
+    if (!htype)      // Don't overwrite original
+    {	if (type)    // Make copy for both old and new instances
+	{   htype = type->syntaxCopy();
+	    st->htype = type->syntaxCopy();
+	}
+    }
+    else            // Make copy of original for new instance
+        st->htype = htype->syntaxCopy();
+    if (!hbasetype)
+    {	if (basetype)
+	{   hbasetype = basetype->syntaxCopy();
+	    st->hbasetype = basetype->syntaxCopy();
+	}
+    }
+    else
+        st->hbasetype = hbasetype->syntaxCopy();
+#endif
+    return st;
+}
+
+void TypedefDeclaration::semantic(Scope *sc)
+{
+    //printf("TypedefDeclaration::semantic(%s) sem = %d\n", toChars(), sem);
+    if (sem == 0)
+    {	sem = 1;
+	basetype = basetype->semantic(loc, sc);
+	sem = 2;
+	type = type->semantic(loc, sc);
+	if (sc->parent->isFuncDeclaration() && init)
+	    semantic2(sc);
+    }
+    else if (sem == 1)
+    {
+	error("circular definition");
+    }
+}
+
+void TypedefDeclaration::semantic2(Scope *sc)
+{
+    //printf("TypedefDeclaration::semantic2(%s) sem = %d\n", toChars(), sem);
+    if (sem == 2)
+    {	sem = 3;
+	if (init)
+	{
+	    init = init->semantic(sc, basetype);
+
+	    ExpInitializer *ie = init->isExpInitializer();
+	    if (ie)
+	    {
+		if (ie->exp->type == basetype)
+		    ie->exp->type = type;
+	    }
+	}
+    }
+}
+
+char *TypedefDeclaration::kind()
+{
+    return "typedef";
+}
+
+Type *TypedefDeclaration::getType()
+{
+    return type;
+}
+
+void TypedefDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("typedef ");
+    basetype->toCBuffer(buf, ident, hgs);
+    if (init)
+    {
+	buf->writestring(" = ");
+	init->toCBuffer(buf, hgs);
+    }
+    buf->writeByte(';');
+    buf->writenl();
+}
+
+/********************************* AliasDeclaration ****************************/
+
+AliasDeclaration::AliasDeclaration(Loc loc, Identifier *id, Type *type)
+    : Declaration(id)
+{
+    //printf("AliasDeclaration(id = '%s', type = %p)\n", id->toChars(), type);
+    //printf("type = '%s'\n", type->toChars());
+    this->loc = loc;
+    this->type = type;
+    this->aliassym = NULL;
+#ifdef _DH
+    this->htype = NULL;
+    this->haliassym = NULL;
+#endif
+    this->overnext = NULL;
+    this->inSemantic = 0;
+    assert(type);
+}
+
+AliasDeclaration::AliasDeclaration(Loc loc, Identifier *id, Dsymbol *s)
+    : Declaration(id)
+{
+    //printf("AliasDeclaration(id = '%s', s = %p)\n", id->toChars(), s);
+    assert(s != this);
+    this->loc = loc;
+    this->type = NULL;
+    this->aliassym = s;
+#ifdef _DH
+    this->htype = NULL;
+    this->haliassym = NULL;
+#endif
+    this->overnext = NULL;
+    this->inSemantic = 0;
+    assert(s);
+}
+
+Dsymbol *AliasDeclaration::syntaxCopy(Dsymbol *s)
+{
+    assert(!s);
+    AliasDeclaration *sa;
+    if (type)
+	sa = new AliasDeclaration(loc, ident, type->syntaxCopy());
+    else
+	sa = new AliasDeclaration(loc, ident, aliassym->syntaxCopy(NULL));
+#ifdef _DH
+    // Syntax copy for header file
+    if (!htype)	    // Don't overwrite original
+    {	if (type)	// Make copy for both old and new instances
+	{   htype = type->syntaxCopy();
+	    sa->htype = type->syntaxCopy();
+	}
+    }
+    else			// Make copy of original for new instance
+	sa->htype = htype->syntaxCopy();
+    if (!haliassym)
+    {	if (aliassym)
+	{   haliassym = aliassym->syntaxCopy(s);
+	    sa->haliassym = aliassym->syntaxCopy(s);
+	}
+    }
+    else
+	sa->haliassym = haliassym->syntaxCopy(s);
+#endif
+    return sa;
+}
+
+void AliasDeclaration::semantic(Scope *sc)
+{
+    //printf("AliasDeclaration::semantic() %s\n", toChars());
+    if (aliassym)
+    {
+	if (aliassym->isTemplateInstance())
+	    aliassym->semantic(sc);
+	return;
+    }
+    this->inSemantic = 1;
+
+    if (storage_class & STCconst)
+	error("cannot be const");
+
+    storage_class |= sc->stc & STCdeprecated;
+
+    // Given:
+    //	alias foo.bar.abc def;
+    // it is not knowable from the syntax whether this is an alias
+    // for a type or an alias for a symbol. It is up to the semantic()
+    // pass to distinguish.
+    // If it is a type, then type is set and getType() will return that
+    // type. If it is a symbol, then aliassym is set and type is NULL -
+    // toAlias() will return aliasssym.
+
+    Dsymbol *s;
+    Type *t;
+    Expression *e;
+
+    /* This section is needed because resolve() will:
+     *   const x = 3;
+     *   alias x y;
+     * try to alias y to 3.
+     */
+    s = type->toDsymbol(sc);
+    if (s)
+	goto L2;			// it's a symbolic alias
+
+    //printf("alias type is %s\n", type->toChars());
+    type->resolve(loc, sc, &e, &t, &s);
+    if (s)
+    {
+	goto L2;
+    }
+    else if (e)
+    {
+	// Try to convert Expression to Dsymbol
+        if (e->op == TOKvar)
+	{   s = ((VarExp *)e)->var;
+	    goto L2;
+	}
+        else if (e->op == TOKfunction)
+	{   s = ((FuncExp *)e)->fd;
+	    goto L2;
+	}
+        else
+	{   error("cannot alias an expression %s", e->toChars());
+	    t = e->type;
+	}
+    }
+    else if (t)
+	type = t;
+    if (overnext)
+	ScopeDsymbol::multiplyDefined(0, this, overnext);
+    this->inSemantic = 0;
+    return;
+
+  L2:
+    //printf("alias is a symbol %s %s\n", s->kind(), s->toChars());
+    type = NULL;
+    VarDeclaration *v = s->isVarDeclaration();
+    if (v && v->linkage == LINKdefault)
+    {
+	error("forward reference of %s", v->toChars());
+	s = NULL;
+    }
+    else
+    {
+	FuncDeclaration *f = s->toAlias()->isFuncDeclaration();
+	if (f)
+	{
+	    if (overnext)
+	    {
+		FuncAliasDeclaration *fa = new FuncAliasDeclaration(f);
+		if (!fa->overloadInsert(overnext))
+		    ScopeDsymbol::multiplyDefined(0, f, overnext);
+		overnext = NULL;
+		s = fa;
+		s->parent = sc->parent;
+	    }
+	}
+	if (overnext)
+	    ScopeDsymbol::multiplyDefined(0, s, overnext);
+	if (s == this)
+	{
+	    assert(global.errors);
+	    s = NULL;
+	}
+    }
+    aliassym = s;
+    this->inSemantic = 0;
+}
+
+int AliasDeclaration::overloadInsert(Dsymbol *s)
+{
+    /* Don't know yet what the aliased symbol is, so assume it can
+     * be overloaded and check later for correctness.
+     */
+
+    //printf("AliasDeclaration::overloadInsert('%s')\n", s->toChars());
+    if (overnext == NULL)
+    {	overnext = s;
+	return TRUE;
+    }
+    else
+    {
+	return overnext->overloadInsert(s);
+    }
+}
+
+char *AliasDeclaration::kind()
+{
+    return "alias";
+}
+
+Type *AliasDeclaration::getType()
+{
+    return type;
+}
+
+Dsymbol *AliasDeclaration::toAlias()
+{
+    //printf("AliasDeclaration::toAlias('%s', this = %p, aliassym = %p, kind = '%s')\n", toChars(), this, aliassym, aliassym ? aliassym->kind() : "");
+    assert(this != aliassym);
+    //static int count; if (++count == 10) *(char*)0=0;
+    if (inSemantic)
+    {	error("recursive alias declaration");
+//	return this;
+    }
+    Dsymbol *s = aliassym ? aliassym->toAlias() : this;
+    return s;
+}
+
+void AliasDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("alias ");
+#if 0 && _DH
+    if (hgs->hdrgen)
+    {
+	if (haliassym)
+	{
+	    haliassym->toCBuffer(buf, hgs);
+	    buf->writeByte(' ');
+	    buf->writestring(ident->toChars());
+	}
+	else
+	    htype->toCBuffer(buf, ident, hgs);
+    }
+    else
+#endif
+    {
+	if (aliassym)
+	{
+	    aliassym->toCBuffer(buf, hgs);
+	    buf->writeByte(' ');
+	    buf->writestring(ident->toChars());
+	}
+	else
+	    type->toCBuffer(buf, ident, hgs);
+    }
+    buf->writeByte(';');
+    buf->writenl();
+}
+
+/********************************* VarDeclaration ****************************/
+
+VarDeclaration::VarDeclaration(Loc loc, Type *type, Identifier *id, Initializer *init)
+    : Declaration(id)
+{
+    //printf("VarDeclaration('%s')\n", id->toChars());
+#ifdef DEBUG
+    if (!type && !init)
+    {	printf("VarDeclaration('%s')\n", id->toChars());
+	//*(char*)0=0;
+    }
+#endif
+    assert(type || init);
+    this->type = type;
+    this->init = init;
+#ifdef _DH
+    this->htype = NULL;
+    this->hinit = NULL;
+#endif
+    this->loc = loc;
+    offset = 0;
+    noauto = 0;
+    nestedref = 0;
+    inuse = 0;
+    ctorinit = 0;
+    aliassym = NULL;
+    onstack = 0;
+    canassign = 0;
+    value = NULL;
+}
+
+Dsymbol *VarDeclaration::syntaxCopy(Dsymbol *s)
+{
+    //printf("VarDeclaration::syntaxCopy(%s)\n", toChars());
+
+    VarDeclaration *sv;
+    if (s)
+    {	sv = (VarDeclaration *)s;
+    }
+    else
+    {
+	Initializer *init = NULL;
+	if (this->init)
+	{   init = this->init->syntaxCopy();
+	    //init->isExpInitializer()->exp->print();
+	    //init->isExpInitializer()->exp->dump(0);
+	}
+
+	sv = new VarDeclaration(loc, type ? type->syntaxCopy() : NULL, ident, init);
+	sv->storage_class = storage_class;
+    }
+#ifdef _DH
+    // Syntax copy for header file
+    if (!htype)      // Don't overwrite original
+    {	if (type)    // Make copy for both old and new instances
+	{   htype = type->syntaxCopy();
+	    sv->htype = type->syntaxCopy();
+	}
+    }
+    else            // Make copy of original for new instance
+        sv->htype = htype->syntaxCopy();
+    if (!hinit)
+    {	if (init)
+	{   hinit = init->syntaxCopy();
+	    sv->hinit = init->syntaxCopy();
+	}
+    }
+    else
+        sv->hinit = hinit->syntaxCopy();
+#endif
+    return sv;
+}
+
+void VarDeclaration::semantic(Scope *sc)
+{
+    //printf("VarDeclaration::semantic('%s', parent = '%s')\n", toChars(), sc->parent->toChars());
+    //printf("type = %s\n", type->toChars());
+    //printf("linkage = %d\n", sc->linkage);
+    //if (strcmp(toChars(), "mul") == 0) halt();
+
+    storage_class |= sc->stc;
+    if (storage_class & STCextern && init)
+	error("extern symbols cannot have initializers");
+
+    /* If auto type inference, do the inference
+     */
+    int inferred = 0;
+    if (!type)
+    {	inuse++;
+	type = init->inferType(sc);
+	inuse--;
+	inferred = 1;
+
+	/* This is a kludge to support the existing syntax for RAII
+	 * declarations.
+	 */
+	storage_class &= ~STCauto;
+    }
+    else
+	type = type->semantic(loc, sc);
+
+    type->checkDeprecated(loc, sc);
+    linkage = sc->linkage;
+    this->parent = sc->parent;
+    //printf("this = %p, parent = %p, '%s'\n", this, parent, parent->toChars());
+    protection = sc->protection;
+    //printf("sc->stc = %x\n", sc->stc);
+    //printf("storage_class = %x\n", storage_class);
+
+    Dsymbol *parent = toParent();
+    FuncDeclaration *fd = parent->isFuncDeclaration();
+
+    Type *tb = type->toBasetype();
+    if (tb->ty == Tvoid && !(storage_class & STClazy))
+    {	error("voids have no value");
+	type = Type::terror;
+	tb = type;
+    }
+    if (tb->ty == Tfunction)
+    {	error("cannot be declared to be a function");
+	type = Type::terror;
+	tb = type;
+    }
+    if (tb->ty == Tstruct)
+    {	TypeStruct *ts = (TypeStruct *)tb;
+
+	if (!ts->sym->members)
+	{
+	    error("no definition of struct %s", ts->toChars());
+	}
+    }
+
+    if (tb->ty == Ttuple)
+    {   /* Instead, declare variables for each of the tuple elements
+	 * and add those.
+	 */
+	TypeTuple *tt = (TypeTuple *)tb;
+	size_t nelems = Argument::dim(tt->arguments);
+	Objects *exps = new Objects();
+	exps->setDim(nelems);
+
+	for (size_t i = 0; i < nelems; i++)
+	{   Argument *arg = Argument::getNth(tt->arguments, i);
+
+	    OutBuffer buf;
+	    buf.printf("_%s_field_%zu", ident->toChars(), i);
+	    buf.writeByte(0);
+	    char *name = (char *)buf.extractData();
+	    Identifier *id = new Identifier(name, TOKidentifier);
+
+	    VarDeclaration *v = new VarDeclaration(loc, arg->type, id, NULL);
+	    //printf("declaring field %s of type %s\n", v->toChars(), v->type->toChars());
+	    v->semantic(sc);
+
+	    if (sc->scopesym)
+	    {	//printf("adding %s to %s\n", v->toChars(), sc->scopesym->toChars());
+		if (sc->scopesym->members)
+		    sc->scopesym->members->push(v);
+	    }
+
+	    Expression *e = new DsymbolExp(loc, v);
+	    exps->data[i] = e;
+	}
+	TupleDeclaration *v2 = new TupleDeclaration(loc, ident, exps);
+	v2->isexp = 1;
+	aliassym = v2;
+	return;
+    }
+
+    if (storage_class & STCconst && !init && !fd)
+	// Initialize by constructor only
+	storage_class = (storage_class & ~STCconst) | STCctorinit;
+
+    if (isConst())
+    {
+    }
+    else if (isStatic())
+    {
+    }
+    else if (isSynchronized())
+    {
+	error("variable %s cannot be synchronized", toChars());
+    }
+    else if (isOverride())
+    {
+	error("override cannot be applied to variable");
+    }
+    else if (isAbstract())
+    {
+	error("abstract cannot be applied to variable");
+    }
+    else if (storage_class & STCtemplateparameter)
+    {
+    }
+    else
+    {
+	AggregateDeclaration *aad = sc->anonAgg;
+	if (!aad)
+	    aad = parent->isAggregateDeclaration();
+	if (aad)
+	{
+	    aad->addField(sc, this);
+	}
+
+	InterfaceDeclaration *id = parent->isInterfaceDeclaration();
+	if (id)
+	{
+	    error("field not allowed in interface");
+	}
+
+	TemplateInstance *ti = parent->isTemplateInstance();
+	if (ti)
+	{
+	    // Take care of nested templates
+	    while (1)
+	    {
+		TemplateInstance *ti2 = ti->tempdecl->parent->isTemplateInstance();
+		if (!ti2)
+		    break;
+		ti = ti2;
+	    }
+
+	    // If it's a member template
+	    AggregateDeclaration *ad = ti->tempdecl->isMember();
+	    if (ad && storage_class != STCundefined)
+	    {
+		error("cannot use template to add field to aggregate '%s'", ad->toChars());
+	    }
+	}
+    }
+
+    if (type->isauto() && !noauto)
+    {
+	if (storage_class & (STCfield | STCout | STCref | STCstatic) || !fd)
+	{
+	    error("globals, statics, fields, ref and out parameters cannot be auto");
+	}
+
+	if (!(storage_class & (STCauto | STCscope)))
+	{
+	    if (!(storage_class & STCparameter) && ident != Id::withSym)
+		error("reference to scope class must be scope");
+	}
+    }
+
+    if (!init && !sc->inunion && !isStatic() && !isConst() && fd &&
+	!(storage_class & (STCfield | STCin | STCforeach)))
+    {
+	// Provide a default initializer
+	//printf("Providing default initializer for '%s'\n", toChars());
+	if (type->ty == Tstruct &&
+	    ((TypeStruct *)type)->sym->zeroInit == 1)
+	{
+	    Expression *e = new IntegerExp(loc, 0, Type::tint32);
+	    Expression *e1;
+	    e1 = new VarExp(loc, this);
+	    e = new AssignExp(loc, e1, e);
+	    e->type = e1->type;
+	    init = new ExpInitializer(loc, e/*->type->defaultInit()*/);
+	    return;
+	}
+	else if (type->ty == Ttypedef)
+	{   TypeTypedef *td = (TypeTypedef *)type;
+	    if (td->sym->init)
+	    {	init = td->sym->init;
+		ExpInitializer *ie = init->isExpInitializer();
+		if (ie)
+		    // Make copy so we can modify it
+		    init = new ExpInitializer(ie->loc, ie->exp);
+	    }
+	    else
+		init = getExpInitializer();
+	}
+	else
+	{
+	    init = getExpInitializer();
+	}
+    }
+
+    if (init)
+    {
+	ArrayInitializer *ai = init->isArrayInitializer();
+	if (ai && type->toBasetype()->ty == Taarray)
+	{
+	    init = ai->toAssocArrayInitializer();
+	}
+
+	ExpInitializer *ei = init->isExpInitializer();
+
+	// See if we can allocate on the stack
+	if (ei && isScope() && ei->exp->op == TOKnew)
+	{   NewExp *ne = (NewExp *)ei->exp;
+	    if (!(ne->newargs && ne->newargs->dim))
+	    {	ne->onstack = 1;
+		onstack = 1;
+		if (type->isBaseOf(ne->newtype->semantic(loc, sc), NULL))
+		    onstack = 2;
+	    }
+	}
+
+	// If inside function, there is no semantic3() call
+	if (sc->func)
+	{
+	    // If local variable, use AssignExp to handle all the various
+	    // possibilities.
+	    if (fd && !isStatic() && !isConst() && !init->isVoidInitializer())
+	    {
+		Expression *e1;
+		Type *t;
+		int dim;
+
+		//printf("fd = '%s', var = '%s'\n", fd->toChars(), toChars());
+		if (!ei)
+		{
+		    Expression *e = init->toExpression();
+		    if (!e)
+		    {
+			init = init->semantic(sc, type);
+			e = init->toExpression();
+			if (!e)
+			{   error("is not a static and cannot have static initializer");
+			    return;
+			}
+		    }
+		    ei = new ExpInitializer(init->loc, e);
+		    init = ei;
+		}
+
+		e1 = new VarExp(loc, this);
+
+		t = type->toBasetype();
+		if (t->ty == Tsarray)
+		{
+		    dim = ((TypeSArray *)t)->dim->toInteger();
+		    // If multidimensional static array, treat as one large array
+		    while (1)
+		    {
+			t = t->next->toBasetype();
+			if (t->ty != Tsarray)
+			    break;
+			if (t->next->toBasetype()->ty == Tbit)
+			    // t->size() gives size in bytes, convert to bits
+			    dim *= t->size() * 8;
+			else
+			    dim *= ((TypeSArray *)t)->dim->toInteger();
+			e1->type = new TypeSArray(t->next, new IntegerExp(0, dim, Type::tindex));
+		    }
+		    e1 = new SliceExp(loc, e1, NULL, NULL);
+		}
+		else if (t->ty == Tstruct)
+		{
+		    ei->exp = ei->exp->semantic(sc);
+		    if (!ei->exp->implicitConvTo(type))
+			ei->exp = new CastExp(loc, ei->exp, type);
+		}
+		ei->exp = new AssignExp(loc, e1, ei->exp);
+		ei->exp->op = TOKconstruct;
+		canassign++;
+		ei->exp = ei->exp->semantic(sc);
+		canassign--;
+		ei->exp->optimize(WANTvalue);
+	    }
+	    else
+	    {
+		init = init->semantic(sc, type);
+		if (fd && isConst() && !isStatic())
+		{   // Make it static
+		    storage_class |= STCstatic;
+		}
+	    }
+	}
+	else if (isConst() || isFinal())
+	{
+	    /* Because we may need the results of a const declaration in a
+	     * subsequent type, such as an array dimension, before semantic2()
+	     * gets ordinarily run, try to run semantic2() now.
+	     * Ignore failure.
+	     */
+
+	    if (ei && !global.errors && !inferred)
+	    {
+		unsigned errors = global.errors;
+		global.gag++;
+		//printf("+gag\n");
+		Expression *e = ei->exp->syntaxCopy();
+		inuse++;
+		e = e->semantic(sc);
+		inuse--;
+		e = e->implicitCastTo(sc, type);
+		global.gag--;
+		//printf("-gag\n");
+		if (errors != global.errors)	// if errors happened
+		{
+		    if (global.gag == 0)
+			global.errors = errors;	// act as if nothing happened
+		}
+		else
+		{
+		    e = e->optimize(WANTvalue | WANTinterpret);
+		    if (e->op == TOKint64 || e->op == TOKstring)
+		    {
+			ei->exp = e;		// no errors, keep result
+		    }
+		}
+	    }
+	}
+    }
+}
+
+ExpInitializer *VarDeclaration::getExpInitializer()
+{
+    ExpInitializer *ei;
+
+    if (init)
+	ei = init->isExpInitializer();
+    else
+    {
+	Expression *e = type->defaultInit();
+	if (e)
+	    ei = new ExpInitializer(loc, e);
+	else
+	    ei = NULL;
+    }
+    return ei;
+}
+
+void VarDeclaration::semantic2(Scope *sc)
+{
+    //printf("VarDeclaration::semantic2('%s')\n", toChars());
+    if (init && !toParent()->isFuncDeclaration())
+    {	inuse++;
+#if 0
+	ExpInitializer *ei = init->isExpInitializer();
+	if (ei)
+	{
+	    ei->exp->dump(0);
+	    printf("type = %p\n", ei->exp->type);
+	}
+#endif
+	init = init->semantic(sc, type);
+	inuse--;
+    }
+}
+
+char *VarDeclaration::kind()
+{
+    return "variable";
+}
+
+Dsymbol *VarDeclaration::toAlias()
+{
+    //printf("VarDeclaration::toAlias('%s', this = %p, aliassym = %p)\n", toChars(), this, aliassym);
+    assert(this != aliassym);
+    Dsymbol *s = aliassym ? aliassym->toAlias() : this;
+    return s;
+}
+
+void VarDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    if (storage_class & STCconst)
+	buf->writestring("const ");
+    if (storage_class & STCstatic)
+	buf->writestring("static ");
+    if (type)
+	type->toCBuffer(buf, ident, hgs);
+    else
+	buf->writestring(ident->toChars());
+    if (init)
+    {	buf->writestring(" = ");
+	init->toCBuffer(buf, hgs);
+    }
+    buf->writeByte(';');
+    buf->writenl();
+}
+
+int VarDeclaration::needThis()
+{
+    //printf("VarDeclaration::needThis(%s, x%x)\n", toChars(), storage_class);
+    return storage_class & STCfield;
+}
+
+int VarDeclaration::isImportedSymbol()
+{
+    if (protection == PROTexport && !init && (isStatic() || isConst() || parent->isModule()))
+	return TRUE;
+    return FALSE;
+}
+
+void VarDeclaration::checkCtorConstInit()
+{
+    if (ctorinit == 0 && isCtorinit() && !(storage_class & STCfield))
+	error("missing initializer in static constructor for const variable");
+}
+
+/************************************
+ * Check to see if variable is a reference to an enclosing function
+ * or not.
+ */
+
+void VarDeclaration::checkNestedReference(Scope *sc, Loc loc)
+{
+    if (!isDataseg() && parent != sc->parent && parent)
+    {
+	FuncDeclaration *fdv = toParent()->isFuncDeclaration();
+	FuncDeclaration *fdthis = sc->parent->isFuncDeclaration();
+
+	if (fdv && fdthis)
+	{
+	    if (loc.filename)
+		fdthis->getLevel(loc, fdv);
+	    nestedref = 1;
+	    fdv->nestedFrameRef = 1;
+	    //printf("var %s in function %s is nested ref\n", toChars(), fdv->toChars());
+	}</